////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2001-2005.
// -------------------------------------------------------------------------
//  File name:   HyperGraphDialog.h
//  Version:     v1.00
//  Created:     21/3/2005 by Timur.
//  Compilers:   Visual Studio.NET 2003
//  Description: 
// -------------------------------------------------------------------------
//  History: 24/09/2008 - Modified by Paulo Zaffari to add multi item 
//                        operations to the flowgraphs.
//
////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include <IAIAction.h>
#include <IAISystem.h>
#include "Ai/AIManager.h"
#include "HyperGraphDialog.h"
#include "IViewPane.h"
#include "MainFrm.h"
#include "HyperGraphManager.h"
#include "UI/UIManager.h"
#include "Material/MaterialFXGraphMan.h"
#include "HyperGraph/FlowGraphModuleManager.h"

#include "FlowGraphManager.h"
#include "FlowGraph.h"
#include "FlowGraphNode.h"
#include "FlowGraphVariables.h"
#include "Objects/EntityObject.h"
#include "Objects/PrefabObject.h"
#include "GameEngine.h"
#include "StringDlg.h"
#include "GenericSelectItemDialog.h"
#include "FlowGraphSearchCtrl.h"
#include "CommentNode.h"
#include "CommentBoxNode.h"
#include "BlackBoxNode.h"
#include "FlowGraphProperties.h"
#include "FlowGraphTokens.h"
#include "FlowGraphModuleDlgs.h"
#include "Dialogs\Generic\StringInputDialog.h"
#include <IAgent.h>
#include <IGameFramework.h>
#include <ILevelSystem.h>
#include <IFlowGraphModuleManager.h>
#include "FlowGraphDebuggerEditor.h"

namespace
{
	const int FlowGraphLayoutVersion = 0x0003; // bump this up on every substantial pane layout change
}

#define GRAPH_FILE_FILTER "Graph XML Files (*.xml)|*.xml"

#define IDW_HYPERGRAPH_RIGHT_PANE  AFX_IDW_CONTROLBAR_FIRST+10
#define IDW_HYPERGRAPH_TREE_PANE  AFX_IDW_CONTROLBAR_FIRST+11
#define IDW_HYPERGRAPH_COMPONENTS_PANE  AFX_IDW_CONTROLBAR_FIRST+12
#define IDW_HYPERGRAPH_SEARCH_PANE  AFX_IDW_CONTROLBAR_FIRST+13
#define IDW_HYPERGRAPH_SEARCHRESULTS_PANE  AFX_IDW_CONTROLBAR_FIRST+14
#define IDW_HYPERGRAPH_BREAKPOINTS_PANE  AFX_IDW_CONTROLBAR_FIRST+15

#define HYPERGRAPH_DIALOGFRAME_CLASSNAME "HyperGraphDialog"

#define IDC_HYPERGRAPH_COMPONENTS 1
#define IDC_HYPERGRAPH_GRAPHS 2
#define IDC_COMPONENT_SEARCH 3
#define IDC_BREAKPOINTS 4

#define ID_PROPERTY_GROUP 1
#define ID_NODE_INFO_GROUP 2
#define ID_GRAPH_INFO_GROUP 3
#define ID_VARIABLES_GROUP 4

#define ID_COMPONENTS_GROUP 1

#define ID_NODE_INFO 100
#define ID_GRAPH_INFO 110


#define IMG_ENTITY		0
#define IMG_AI				1
#define IMG_FOLDER		2
#define IMG_DEFAULT		3
#define IMG_BIGX			4
#define IMG_SMALLX		5
#define IMG_UI				6
#define IMG_FX				7
#define IMG_FM				8
#define IMG_ERROR_OFFSET	9

namespace {
	const char* g_EntitiesFolderName = "Entities";
	const char* g_AIActionsFolderName = "AI Actions";
	const char* g_UIActionsFolderName = "UI Actions";
	const char* g_FGModulesFolderName = "FG Modules";
	const char* g_MaterialFXFolderName = "Material FX";
	
	void GetPrettyName(CHyperGraph* pGraph, CString& name, CString& groupName)
	{
		if (!pGraph->IsFlowGraph()) 
		{
			name = "";
			groupName = "";
			return;
		}
		CFlowGraph *pFlowGraph = static_cast<CFlowGraph*> (pGraph);
		CEntityObject *pEntity = pFlowGraph->GetEntity();
		IFlowGraph::EFlowGraphType type = pFlowGraph->GetIFlowGraph()->GetType();
		const CRuntimeClass* pPrefabClass = RUNTIME_CLASS(CPrefabObject);

		if (type == IFlowGraph::eFGT_Default && pEntity)
		{
			if (pEntity->IsInGroup())
			{
				CGroup* pObjGroup = pEntity->GetGroup();
				if (pObjGroup)
				{
					groupName = pObjGroup->GetName();
					name = pEntity->GetName();
				}
				else
				{
					name = "";
					groupName = "";
				}
			}
			else
			{
				name = pEntity->GetName();
				if (!pFlowGraph->GetGroupName().IsEmpty())
					groupName = pFlowGraph->GetGroupName();
				else
					groupName = g_EntitiesFolderName;
			}
		}
		else if (type == IFlowGraph::eFGT_AIAction)
		{
			IAIAction *pAIAction = pFlowGraph->GetAIAction();
			assert(pAIAction);
			if (pAIAction)
			{
				name = pAIAction->GetName();
				if (!pFlowGraph->GetGroupName().IsEmpty())
					groupName = pFlowGraph->GetGroupName();
				else
					groupName = g_AIActionsFolderName;
			}
		}
		else if (type == IFlowGraph::eFGT_UIAction)
		{
			IUIAction *pUIAction = pFlowGraph->GetUIAction();
			assert(pUIAction);
			if (pUIAction)
			{
				name = pUIAction->GetName();
				if (!pFlowGraph->GetGroupName().IsEmpty())
					groupName = pFlowGraph->GetGroupName();
				else
					groupName = g_UIActionsFolderName;
			}
		}
		else if (type == IFlowGraph::eFGT_MaterialFx)
		{
			name = pFlowGraph->GetName();
			if (!pFlowGraph->GetGroupName().IsEmpty())
				groupName = pFlowGraph->GetGroupName();
			else
				groupName = g_MaterialFXFolderName;
		}
		else if (type == IFlowGraph::eFGT_Module)
		{
			name = pFlowGraph->GetName();
			if (!pFlowGraph->GetGroupName().IsEmpty())
				groupName = pFlowGraph->GetGroupName();
			else
				groupName = g_FGModulesFolderName;
		}
		else
		{
			name = pFlowGraph->GetName();
			groupName = "Files";
		}
	}

}

//////////////////////////////////////////////////////////////////////////
//
// CHyperGraphsTreeCtrl
//
//////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP(CHyperGraphsTreeCtrl, CXTTreeCtrl)
	ON_WM_ERASEBKGND()
END_MESSAGE_MAP()

//////////////////////////////////////////////////////////////////////////
CHyperGraphsTreeCtrl::CHyperGraphsTreeCtrl():m_pCurrentGraph(NULL)
{
	m_bIgnoreReloads = false;
	GetIEditor()->GetFlowGraphManager()->AddListener(this);
	int nSize = sizeof(&CHyperGraphsTreeCtrl::OnObjectEvent);
	GetIEditor()->GetObjectManager()->AddObjectEventListener( functor(*this,&CHyperGraphsTreeCtrl::OnObjectEvent) );
}

//////////////////////////////////////////////////////////////////////////
CHyperGraphsTreeCtrl::~CHyperGraphsTreeCtrl()
{
//	GetIEditor()->GetAI()->SaveActionGraphs();
	GetIEditor()->GetFlowGraphManager()->RemoveListener(this);
	GetIEditor()->GetObjectManager()->RemoveObjectEventListener( functor(*this,&CHyperGraphsTreeCtrl::OnObjectEvent) );
}

//////////////////////////////////////////////////////////////////////////
BOOL CHyperGraphsTreeCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
	BOOL ret = __super::Create( dwStyle|WS_BORDER|TVS_HASBUTTONS|TVS_LINESATROOT|TVS_HASLINES|TVS_SHOWSELALWAYS,rect,pParentWnd,nID );

	CMFCUtils::LoadTrueColorImageList( m_imageList,IDB_HYPERGRAPH_TREE,16,RGB(255,0,255) );
	//m_imageList.Create( MAKEINTRESOURCE(IDB_HYPERGRAPH_TREE),16,1,RGB(255,0,255) );
	SetImageList( &m_imageList,TVSIL_NORMAL );
	return ret;
}

//////////////////////////////////////////////////////////////////////////
BOOL CHyperGraphsTreeCtrl::OnEraseBkgnd(CDC* pDC)
{
	//if (m_bReloadGraphs)
	//	Reload();
	return __super::OnEraseBkgnd(pDC);
}

HTREEITEM FindItemByData( CTreeCtrl* pTreeCtrl, HTREEITEM hItem, DWORD_PTR data )
{
	while ( hItem )
	{
		if ( pTreeCtrl->GetItemData( hItem ) == data )
			return hItem;
		else
		{
			HTREEITEM temp = FindItemByData( pTreeCtrl, pTreeCtrl->GetChildItem( hItem ), data );
			if ( temp )
				return temp;
		}
		hItem = pTreeCtrl->GetNextSiblingItem(hItem);
	}
	return NULL;
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphsTreeCtrl::SetCurrentGraph( CHyperGraph *pCurrentGraph )
{
	m_pCurrentGraph = pCurrentGraph;
	if (m_hWnd)
	{
		CTreeCtrl *pTreeCtrl = this;

		HTREEITEM hItem = FindItemByData( pTreeCtrl, pTreeCtrl->GetRootItem(), (DWORD_PTR) pCurrentGraph );
		if ( hItem )
		{
			// all parent nodes have to be expanded first
			HTREEITEM hParent = hItem;
			while ( hParent = pTreeCtrl->GetParentItem( hParent ) )
				pTreeCtrl->Expand( hParent, TVE_EXPAND );

			pTreeCtrl->Select( hItem, TVGN_CARET );
			pTreeCtrl->EnsureVisible( hItem );
		}
	}
}

HTREEITEM CHyperGraphsTreeCtrl::GetTreeItem(CHyperGraph* pGraph)
{
	if (m_hWnd)
	{
		CTreeCtrl *pTreeCtrl = this;
		HTREEITEM hItem = FindItemByData( pTreeCtrl, pTreeCtrl->GetRootItem(), (DWORD_PTR) pGraph );
		return hItem;
	}
	return 0;
}

BOOL CHyperGraphsTreeCtrl::DeleteNonEntityItem(CHyperGraph* pGraph, HTREEITEM& hAdjacentItem)
{
	if( pGraph == NULL )
		return FALSE;

	HTREEITEM hItem = GetTreeItem(pGraph);

	if( hItem == NULL )
	{
		return FALSE;
	}
	else 
	{
		hAdjacentItem = GetNextSiblingItem(hItem);
		if( hAdjacentItem == NULL )
		{
			hAdjacentItem = GetPrevSiblingItem(hItem);
			if( hAdjacentItem == NULL )
			{
				hAdjacentItem = GetParentItem(hItem);
				if( hAdjacentItem == NULL )
					hAdjacentItem = GetRootItem();
			}
		}

		if(DeleteItem(hItem))
			return TRUE;
	}

	return FALSE;
}


BOOL CHyperGraphsTreeCtrl::DeleteEntityItem(CEntityObject* pEntity, HTREEITEM& hAdjacentItem)
{
	if( pEntity == NULL )
		return FALSE;

	CHyperGraph* pGraph = pEntity->GetFlowGraph();
	
	if( pGraph == NULL )
		return FALSE;
	
	HTREEITEM hItem = GetTreeItem(pGraph);
	if( hItem == NULL )
	{
		return FALSE;
	}
	else 
	{	
		hAdjacentItem = GetNextSiblingItem(hItem);
		if( hAdjacentItem == NULL )
		{
			hAdjacentItem = GetPrevSiblingItem(hItem);
			if( hAdjacentItem == NULL )
			{
					hAdjacentItem = GetParentItem(hItem);
					if( hAdjacentItem == NULL )
						hAdjacentItem = GetRootItem();
			}
		}

		if( DeleteItem(hItem) )
		{
			if( m_mapEntityToItem.find(pEntity) != m_mapEntityToItem.end() )
				m_mapEntityToItem.erase(pEntity);
			
			CPrefabObject* pPrefab = (CPrefabObject*)pEntity->GetGroup();
			if( pPrefab && m_mapPrefabToItem.find(pPrefab) != m_mapPrefabToItem.end() )
				m_mapPrefabToItem.erase(pPrefab);

			return TRUE;
		}
	}
	return FALSE;
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphsTreeCtrl::GetSelectedItems(TDTreeItems& rchSelectedTreeItems)
{
	CPoint point;
	GetCursorPos(&point);

	ScreenToClient(&point);

	HTREEITEM hCurrentItem=GetFirstSelectedItem();

	if (hCurrentItem==NULL)
	{
		return;
	}
	else
	{
		do
		{
			rchSelectedTreeItems.push_back(hCurrentItem);
			hCurrentItem=GetNextSelectedItem(hCurrentItem);
		} while(hCurrentItem);		
	}
}
//////////////////////////////////////////////////////////////////////////

struct SHGTCReloadItem
{
	SHGTCReloadItem( CString name,  CString groupName, HTREEITEM parent,int nImage, CFlowGraph * pFlowGraph, CEntityObject * pEntity = NULL )
	{
		// this->name.Format("0x%p %s", pFlowGraph, name.GetString());
		this->name = name;
		this->groupName = groupName;
		this->parent = parent;
		this->pFlowGraph = pFlowGraph;
		this->pEntity = pEntity;
		this->nImage = nImage;
	}
	CString name;
	CString groupName;
	HTREEITEM parent;
	CFlowGraph * pFlowGraph;
	CEntityObject * pEntity;
	int nImage;

	bool operator<( const SHGTCReloadItem& rhs ) const
	{
		int cmpResult = groupName.CompareNoCase(rhs.groupName);
		if (cmpResult!=0)
			return cmpResult < 0;
		return name.CompareNoCase(rhs.name) < 0;
	}

	HTREEITEM Add( CHyperGraphsTreeCtrl* pCtrl )
	{
		HTREEITEM hItem = pCtrl->InsertItem( name, nImage, nImage, parent);
		pCtrl->SetItemData( hItem, DWORD_PTR(pFlowGraph) );
		/*
		if (!pFlowGraph->IsEnabled())
		{
		LOGFONT logfont;
		pCtrl->GetItemFont( hItem,&logfont );
		logfont.lfStrikeOut = 1;
		pCtrl->SetItemFont( hItem,logfont );
		}
		*/
		return hItem;
	}

};

//////////////////////////////////////////////////////////////////////////
void CHyperGraphsTreeCtrl::Reload()
{
	std::vector<SHGTCReloadItem> items;
	CTreeCtrl *pTreeCtrl = this;
	SetRedraw(FALSE);

	DeleteAllItems();

	CFlowGraphManager *pMgr = GetIEditor()->GetFlowGraphManager();

	m_mapEntityToItem.clear();
	m_mapPrefabToItem.clear();

	HTREEITEM hActionsGroup = NULL;
	if ( GetISystem()->GetIFlowSystem() && GetISystem()->GetAISystem() )
	{
		hActionsGroup = pTreeCtrl->InsertItem( g_AIActionsFolderName,IMG_AI,IMG_AI );
		int i = 0;
		IAIAction* pAction;
		while ( pAction = gEnv->pAISystem->GetAIActionManager()->GetAIAction(i++) )
		{
			IFlowGraph* pActionGraph = pAction->GetFlowGraph();
		}
	}

	HTREEITEM hUIGroup = NULL;
	if ( GetIEditor()->GetUIManager()->IsFlashEnabled() )
		hUIGroup = pTreeCtrl->InsertItem( g_UIActionsFolderName, IMG_UI,IMG_UI);

	HTREEITEM hMatFXGroup = pTreeCtrl->InsertItem( g_MaterialFXFolderName, IMG_FX,IMG_FX);

	HTREEITEM hFGModulesGroup = pTreeCtrl->InsertItem( g_FGModulesFolderName, IMG_FM,IMG_FM);

	HTREEITEM hGlobalFGModules = pTreeCtrl->InsertItem("Global", IMG_FOLDER, IMG_FOLDER, hFGModulesGroup, TVI_SORT );;
	HTREEITEM hLevelFGModules = pTreeCtrl->InsertItem("Level", IMG_FOLDER, IMG_FOLDER, hFGModulesGroup, TVI_SORT );;
	
	HTREEITEM hEntityGroup = pTreeCtrl->InsertItem( g_EntitiesFolderName,IMG_FOLDER,IMG_FOLDER );
	HTREEITEM hSharedGroup = pTreeCtrl->InsertItem( "Files",IMG_FOLDER,IMG_FOLDER );
	HTREEITEM hPrefabGroup = pTreeCtrl->InsertItem( "Prefabs", IMG_FOLDER,IMG_FOLDER);

	const CRuntimeClass* pPrefabClass = RUNTIME_CLASS(CPrefabObject);

	pTreeCtrl->Expand(hEntityGroup,TVE_EXPAND);

	std::map<CString,HTREEITEM,stl::less_stricmp<CString> > groups[4];

	HTREEITEM hSelectedItem = 0;
	for (int i = 0; i < pMgr->GetFlowGraphCount(); i++)
	{
		CFlowGraph *pFlowGraph = pMgr->GetFlowGraph(i);
		CEntityObject *pEntity = pFlowGraph->GetEntity();
		IFlowGraph::EFlowGraphType type = pFlowGraph->GetIFlowGraph()->GetType();

		const char* szGroupName;
		const bool bHasError = pFlowGraph->HasError();
		const	int img_offset = bHasError ? IMG_ERROR_OFFSET : 0;

		if (type == IFlowGraph::eFGT_Default && pEntity)
		{
			if (pEntity->IsInGroup() || pEntity->CheckFlags(OBJFLAG_PREFAB))
			{
				CGroup* pObjGroup = pEntity->GetGroup();
				assert (pObjGroup != 0);
				if (pObjGroup == 0)
				{
					CryLogAlways("CHyperGraphsTreeCtrl::Reload(): Entity %p (%s) in Group but GroupPtr is 0",
						pEntity, pEntity->GetName().GetString());
					continue;
				}
				if (!pObjGroup->IsOpen())
					continue;

				if (pObjGroup->IsKindOf(pPrefabClass) || pEntity->CheckFlags(OBJFLAG_PREFAB))
				{
					CPrefabObject *pPrefab = (CPrefabObject*) pObjGroup;

					const CString& pfGroupName = pObjGroup ? pObjGroup->GetName() : "<unknown PREFAB>";







					HTREEITEM hGroup = stl::find_in_map( groups[3],pfGroupName,NULL );
					if (!hGroup && !pfGroupName.IsEmpty())
					{
						hGroup = pTreeCtrl->InsertItem( pfGroupName,IMG_FOLDER,IMG_FOLDER,hPrefabGroup, TVI_SORT );
						groups[3][pfGroupName] = hGroup;
						m_mapPrefabToItem[pPrefab] = hGroup;
					}
					if (bHasError)
					{
						if (hGroup)
							SetItemImage(hGroup, IMG_FOLDER+IMG_ERROR_OFFSET, IMG_FOLDER+IMG_ERROR_OFFSET);
						SetItemImage(hPrefabGroup, IMG_FOLDER+IMG_ERROR_OFFSET, IMG_FOLDER+IMG_ERROR_OFFSET);
					}
					if (!hGroup)
					{
						hGroup = hPrefabGroup;
						szGroupName = "Prefabs";
					}
					else
						szGroupName = pfGroupName.GetString();
					items.push_back(SHGTCReloadItem(pEntity->GetName(), szGroupName, hGroup, pFlowGraph->IsEnabled() ? IMG_ENTITY+img_offset : IMG_BIGX+img_offset, pFlowGraph, pEntity));
				}
				else
				{
					// entity is in a group, but not in a prefab
					CryLogAlways("CHyperGraphsTreeCtrl::Reload(): Entity %p (%s) in Group but not a Prefab",
						pEntity, pEntity->GetName().GetString());

					HTREEITEM hGroup = stl::find_in_map( groups[0],pFlowGraph->GetGroupName(),NULL );
					if (!hGroup && !pFlowGraph->GetGroupName().IsEmpty())
					{
						hGroup = pTreeCtrl->InsertItem( pFlowGraph->GetGroupName(),IMG_FOLDER,IMG_FOLDER,hEntityGroup, TVI_SORT );
						groups[0][pFlowGraph->GetGroupName()] = hGroup;
					}
					if (bHasError)
					{
						if (hGroup)
							SetItemImage(hGroup, IMG_FOLDER+IMG_ERROR_OFFSET, IMG_FOLDER+IMG_ERROR_OFFSET);
						SetItemImage(hEntityGroup, IMG_FOLDER+IMG_ERROR_OFFSET, IMG_FOLDER+IMG_ERROR_OFFSET);
					}
					if (!hGroup)
					{
						hGroup = hEntityGroup;
						szGroupName = g_EntitiesFolderName;
					}
					else
						szGroupName = pFlowGraph->GetGroupName().GetString();
					CString reloadName = "[";
					reloadName+=pObjGroup->GetName();
					reloadName+="] ";
					reloadName+=pEntity->GetName();
					items.push_back(SHGTCReloadItem(reloadName, szGroupName, hGroup, pFlowGraph->IsEnabled() ? IMG_ENTITY+img_offset : IMG_BIGX+img_offset, pFlowGraph, pEntity));
				}
			}
			else
			{
				HTREEITEM hGroup = stl::find_in_map( groups[0],pFlowGraph->GetGroupName(),NULL );
				if (!hGroup && !pFlowGraph->GetGroupName().IsEmpty())
				{
					hGroup = pTreeCtrl->InsertItem( pFlowGraph->GetGroupName(),IMG_FOLDER,IMG_FOLDER,hEntityGroup, TVI_SORT );
					groups[0][pFlowGraph->GetGroupName()] = hGroup;
				}
				if (bHasError)
				{
					if (hGroup)
						SetItemImage(hGroup, IMG_FOLDER+IMG_ERROR_OFFSET, IMG_FOLDER+IMG_ERROR_OFFSET);
					SetItemImage(hEntityGroup, IMG_FOLDER+IMG_ERROR_OFFSET, IMG_FOLDER+IMG_ERROR_OFFSET);
				}
				if (!hGroup)
				{
					hGroup = hEntityGroup;
					szGroupName = g_EntitiesFolderName;
				}
				else
					szGroupName = pFlowGraph->GetGroupName().GetString();
				items.push_back(SHGTCReloadItem(pEntity->GetName(), szGroupName, hGroup, pFlowGraph->IsEnabled() ? IMG_ENTITY+img_offset : IMG_BIGX+img_offset, pFlowGraph, pEntity));
			}
		}
		else if (type == IFlowGraph::eFGT_AIAction)
		{
			IAIAction *pAIAction = pFlowGraph->GetAIAction();
			if ( !pAIAction || pAIAction->GetUserEntity() || pAIAction->GetObjectEntity() )
				continue;

			HTREEITEM hGroup = stl::find_in_map( groups[1],pFlowGraph->GetGroupName(),NULL );
			if (!hGroup && !pFlowGraph->GetGroupName().IsEmpty())
			{
				hGroup = pTreeCtrl->InsertItem( pFlowGraph->GetGroupName(),IMG_FOLDER,IMG_FOLDER,hActionsGroup, TVI_SORT );
				groups[1][pFlowGraph->GetGroupName()] = hGroup;
				szGroupName = pFlowGraph->GetGroupName().GetString();
			}
			if (bHasError)
			{
				if (hGroup)
					SetItemImage(hGroup, IMG_FOLDER+IMG_ERROR_OFFSET, IMG_FOLDER+IMG_ERROR_OFFSET);
				SetItemImage(hActionsGroup, IMG_AI+IMG_ERROR_OFFSET, IMG_AI+IMG_ERROR_OFFSET);
			}
			if (!hGroup)
			{
				hGroup = hActionsGroup;
				szGroupName = g_AIActionsFolderName;
			}
			else
				szGroupName = pFlowGraph->GetGroupName().GetString();
			items.push_back(SHGTCReloadItem(pAIAction->GetName(), szGroupName, hGroup, IMG_AI+img_offset, pFlowGraph));
		}
		else if (type == IFlowGraph::eFGT_UIAction)
		{
			IUIAction *pUIAction = pFlowGraph->GetUIAction();
			assert(pUIAction);
			if (!pUIAction) continue;

			HTREEITEM hGroup = stl::find_in_map( groups[1],pFlowGraph->GetGroupName(),NULL );
			if (!hGroup && !pFlowGraph->GetGroupName().IsEmpty())
			{
				hGroup = pTreeCtrl->InsertItem( pFlowGraph->GetGroupName(),IMG_FOLDER,IMG_FOLDER,hUIGroup, TVI_SORT );
				groups[1][pFlowGraph->GetGroupName()] = hGroup;
				szGroupName = pFlowGraph->GetGroupName().GetString();
			}
			if (bHasError)
			{
				if (hGroup)
					SetItemImage(hGroup, IMG_FOLDER+IMG_ERROR_OFFSET, IMG_FOLDER+IMG_ERROR_OFFSET);
				SetItemImage(hUIGroup, IMG_UI+IMG_ERROR_OFFSET, IMG_UI+IMG_ERROR_OFFSET);
			}
			if (!hGroup)
			{
				hGroup = hUIGroup;
				szGroupName = g_UIActionsFolderName;
			}
			else
				szGroupName = pFlowGraph->GetGroupName().GetString();
			items.push_back(SHGTCReloadItem(pUIAction->GetName(), szGroupName, hGroup, IMG_UI+img_offset, pFlowGraph));
		}
		else if (type == IFlowGraph::eFGT_Module)
		{
			if(IFlowGraphModule* pModule = gEnv->pFlowSystem->GetIModuleManager()->GetModule(pFlowGraph->GetName()))
			{
				IFlowGraphModule::EType moduleType = pModule->GetType();
				const bool bGlobal = (moduleType == IFlowGraphModule::eT_Global);

				HTREEITEM hGroup = stl::find_in_map( groups[1],pFlowGraph->GetGroupName(),NULL );
				if (!hGroup && !pFlowGraph->GetGroupName().IsEmpty())
				{
					hGroup = pTreeCtrl->InsertItem( pFlowGraph->GetGroupName(),IMG_FOLDER,IMG_FOLDER, bGlobal ? hGlobalFGModules : hLevelFGModules, TVI_SORT );
					groups[1][pFlowGraph->GetGroupName()] = hGroup;
					szGroupName = pFlowGraph->GetGroupName().GetString();
				}
				if (bHasError)
				{
					if (hGroup)
						SetItemImage(hGroup, IMG_FOLDER+IMG_ERROR_OFFSET, IMG_FOLDER+IMG_ERROR_OFFSET);
					SetItemImage(hFGModulesGroup, IMG_FM+IMG_ERROR_OFFSET, IMG_FM+IMG_ERROR_OFFSET);
				}
				if (!hGroup)
				{
					hGroup = bGlobal ? hGlobalFGModules : hLevelFGModules;
					szGroupName = g_FGModulesFolderName;
				}
				else
					szGroupName = pFlowGraph->GetGroupName().GetString();
				items.push_back(SHGTCReloadItem(pFlowGraph->GetName(), szGroupName, hGroup, IMG_FM+img_offset, pFlowGraph));
			}
		}
		else if (type == IFlowGraph::eFGT_MaterialFx)
		{
			HTREEITEM hGroup = stl::find_in_map( groups[1],pFlowGraph->GetGroupName(),NULL );
			if (!hGroup && !pFlowGraph->GetGroupName().IsEmpty())
			{
				hGroup = pTreeCtrl->InsertItem( pFlowGraph->GetGroupName(),IMG_FOLDER,IMG_FOLDER,hMatFXGroup, TVI_SORT );
				groups[1][pFlowGraph->GetGroupName()] = hGroup;
				szGroupName = pFlowGraph->GetGroupName().GetString();
			}
			if (bHasError)
			{
				if (hGroup)
					SetItemImage(hGroup, IMG_FOLDER+IMG_ERROR_OFFSET, IMG_FOLDER+IMG_ERROR_OFFSET);
				SetItemImage(hMatFXGroup, IMG_FX+IMG_ERROR_OFFSET, IMG_FX+IMG_ERROR_OFFSET);
			}
			if (!hGroup)
			{
				hGroup = hMatFXGroup;
				szGroupName = g_MaterialFXFolderName;
			}
			else
				szGroupName = pFlowGraph->GetGroupName().GetString();
			items.push_back(SHGTCReloadItem(pFlowGraph->GetName(), szGroupName, hGroup, IMG_FX+img_offset, pFlowGraph));
		}
		else
		{
			HTREEITEM hGroup = stl::find_in_map( groups[2],pFlowGraph->GetGroupName(),NULL );
			if (!hGroup && !pFlowGraph->GetGroupName().IsEmpty())
			{
				hGroup = pTreeCtrl->InsertItem( pFlowGraph->GetGroupName(),IMG_FOLDER,IMG_FOLDER,hSharedGroup, TVI_SORT );
				groups[2][pFlowGraph->GetGroupName()] = hGroup;
				szGroupName = pFlowGraph->GetGroupName().GetString();
			}
			if (bHasError)
			{
				if (hGroup)
					SetItemImage(hGroup, IMG_FOLDER+IMG_ERROR_OFFSET, IMG_FOLDER+IMG_ERROR_OFFSET);

				SetItemImage(hSharedGroup, IMG_FOLDER+IMG_ERROR_OFFSET, IMG_FOLDER+IMG_ERROR_OFFSET);
			}
			if (!hGroup)
			{
				hGroup = hSharedGroup;
				szGroupName = "Files";
			}
			else
			{
				szGroupName = pFlowGraph->GetGroupName().GetString();
			}
			items.push_back(SHGTCReloadItem(pFlowGraph->GetName(), szGroupName, hGroup, pFlowGraph->IsEnabled() ? IMG_DEFAULT+img_offset : IMG_SMALLX+img_offset, pFlowGraph));
		}
	}

	std::sort( items.begin(), items.end() );
	for (size_t i=0; i<items.size(); ++i)
	{
		HTREEITEM hItem = items[i].Add( this );
		if (items[i].pEntity)
		{
			m_mapEntityToItem[items[i].pEntity] = hItem;
		}
		if (m_pCurrentGraph && (m_pCurrentGraph == items[i].pFlowGraph))
		{
			hSelectedItem = hItem;
		}
	}

	if (hSelectedItem)
	{
		pTreeCtrl->SelectItem( hSelectedItem );
	}

	SetRedraw(TRUE);
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphsTreeCtrl::OnHyperGraphManagerEvent( EHyperGraphEvent event, IHyperGraph* pGraph, IHyperNode* pNode )
{
	if (m_bIgnoreReloads == true)
		return;

	switch (event)
	{
	case EHG_GRAPH_ADDED:
	case EHG_GRAPH_OWNER_CHANGE:
		Reload();
		Invalidate(TRUE);
		break;
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphsTreeCtrl::OnObjectEvent( CBaseObject *pObject,int nEvent )
{
	switch (nEvent)
	{
	case CBaseObject::ON_RENAME:
		if (pObject->IsKindOf(RUNTIME_CLASS(CEntityObject)))
		{
			HTREEITEM hItem = stl::find_in_map( m_mapEntityToItem,(CEntityObject*)pObject,NULL );
			if (hItem)
			{
				// Rename this item.
				SetItemText( hItem,pObject->GetName() );
				HTREEITEM hParent = this->GetParentItem(hItem);
				if (hParent)
				{
					SortChildren(hParent);
				}
			}
		}
		else if (pObject->IsKindOf(RUNTIME_CLASS(CPrefabObject)))
		{
			HTREEITEM hItem = stl::find_in_map (m_mapPrefabToItem, (CPrefabObject*)pObject, NULL);
			if (hItem)
			{
				SetItemText( hItem,pObject->GetName() );
				HTREEITEM hParent = this->GetParentItem(hItem);
				if (hParent)
				{
					SortChildren(hParent);
				}
				CWnd *pWnd = GetIEditor()->FindView( "Flow Graph" );
				if (pWnd != 0 && pWnd->IsKindOf(RUNTIME_CLASS(CHyperGraphDialog)))
				{
					((CHyperGraphDialog*)pWnd)->GetGraphView()->InvalidateView(true);
				}
			}
		}
		break;


	case CBaseObject::ON_ADD:
		if (pObject->IsKindOf(RUNTIME_CLASS(CPrefabObject)))
		{
			CPrefabObject* pPrefab = (CPrefabObject*) pObject;
			// get all children and see if one Entity is there, which we already know of.
			// not very efficient...
			struct Recurser
			{
				Recurser(std::map<CEntityObject*,HTREEITEM>& mapEntityToItem)
					: m_mapEntityToItem(mapEntityToItem), m_bHasFG(false), m_bAbort(false) {}
				inline void DoIt(CBaseObject* pObject)
				{
					if (pObject->IsKindOf(RUNTIME_CLASS(CEntityObject)) == false)
						return;

					HTREEITEM hEntityItem = stl::find_in_map( m_mapEntityToItem,(CEntityObject*)pObject,NULL );
					m_bHasFG = (hEntityItem != 0);
					m_bAbort = m_bHasFG;
				}
				void Recurse(CBaseObject* pObject)
				{
					DoIt(pObject);
					if (m_bAbort)
						return;
					int nChilds = pObject->GetChildCount();
					for (int i = 0; i < nChilds; ++i)
					{
						Recurse( pObject->GetChild(i));
						if (m_bAbort)
							return;
					}
				}
				std::map<CEntityObject*,HTREEITEM>& m_mapEntityToItem;
				bool m_bHasFG;
				bool m_bAbort;
			};

			Recurser recurser(m_mapEntityToItem);
			recurser.Recurse(pPrefab);
			if (recurser.m_bHasFG)
				Reload();
		}
		break;
	}
}

//////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP( CHyperGraphComponentsReportCtrl, CXTPReportControl )
	ON_WM_LBUTTONDOWN( )
	ON_WM_LBUTTONUP( )
	ON_WM_MOUSEMOVE( )
	ON_WM_CAPTURECHANGED( )
	ON_WM_DESTROY ( )
	ON_NOTIFY_REFLECT(XTP_NM_REPORT_HEADER_RCLICK, OnReportColumnRClick)
	ON_NOTIFY_REFLECT(NM_DBLCLK, OnReportItemDblClick)
	ON_WM_RBUTTONDOWN()
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////////

class CMyPaintManager : public CXTPReportPaintManager
{
public:
	CMyPaintManager() : m_bHeaderVisible(true) {}

	virtual void DrawColumn(
		CDC* pDC, 
		CXTPReportColumn* pColumn, 
		CXTPReportHeader* pHeader, 
		CRect rcColumn, 
		BOOL bDrawExternal
		)
	{
		if (m_bHeaderVisible)
			__super::DrawColumn(pDC,pColumn,pHeader,rcColumn,bDrawExternal);
	}

	virtual int GetRowHeight(CDC* pDC, CXTPReportRow* pRow)
	{
		return __super::GetRowHeight(pDC,pRow) - 2;
	}

	virtual int GetHeaderHeight()
	{
		if (m_bHeaderVisible) 
			return __super::GetHeaderHeight();
		else
			return 0;
	}
	bool m_bHeaderVisible;
};

//////////////////////////////////////////////////////////////////////////
CHyperGraphComponentsReportCtrl::CHyperGraphComponentsReportCtrl()
{
	m_pDialog = 0;

	CMFCUtils::LoadTrueColorImageList( m_imageList,IDB_HYPERGRAPH_COMPONENTS,16,RGB(255,0,255) );
	SetImageList(&m_imageList);

	CXTPReportColumn *pNodeCol   = AddColumn(new CXTPReportColumn(0, _T("NodeClass"), 150, TRUE, XTP_REPORT_NOICON, TRUE, TRUE));
	CXTPReportColumn *pCatCol    = AddColumn(new CXTPReportColumn(1, _T("Category"), 50, TRUE, XTP_REPORT_NOICON, TRUE, TRUE));
	//CXTPReportColumn *pNodeCol    = AddColumn(new CXTPReportColumn(1, _T("Node"), 50, TRUE, XTP_REPORT_NOICON, TRUE, TRUE));
	//GetColumns()->GetGroupsOrder()->Add(pGraphCol);
	pNodeCol->SetTreeColumn(true);
	pNodeCol->SetSortable(FALSE);
	pCatCol->SetSortable(FALSE);
	GetColumns()->SetSortColumn(pNodeCol, true);
	GetReportHeader()->AllowColumnRemove(FALSE);
	ShadeGroupHeadings(FALSE);
	SkipGroupsFocus(TRUE);
	SetMultipleSelection(FALSE);

	m_bDragging = false;
	m_bDragEx = false;
	m_ptDrag.SetPoint(0,0);

	CXTPReportPaintManager* pPMgr = new CMyPaintManager();
	pPMgr->m_nTreeIndent = 0x0f;
	pPMgr->m_bShadeSortColumn = false;
	pPMgr->m_strNoItems = _T("Use View->Components menu\nto show items");
	pPMgr->SetGridStyle(FALSE, xtpGridNoLines);
	pPMgr->SetGridStyle(TRUE, xtpGridNoLines);
	SetPaintManager( pPMgr );

	CXTRegistryManager regMgr;
	int showHeader = regMgr.GetProfileInt(_T("FlowGraph"), _T("ComponentShowHeader"), 1);
	SetHeaderVisible(showHeader != 0);
}

//////////////////////////////////////////////////////////////////////////
bool CHyperGraphComponentsReportCtrl::IsHeaderVisible()
{
	return m_bHeaderVisible;
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphComponentsReportCtrl::SetHeaderVisible(bool bVisible)
{
	CMyPaintManager* pPMgr = static_cast<CMyPaintManager*> (GetPaintManager());
	pPMgr->m_bHeaderVisible = bVisible;
	m_bHeaderVisible = bVisible;
	// when the header is hidden, we also hide the Category column
	GetColumns()->GetAt(1)->SetVisible(m_bHeaderVisible);
}


//////////////////////////////////////////////////////////////////////////
CHyperGraphComponentsReportCtrl::~CHyperGraphComponentsReportCtrl()
{
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphComponentsReportCtrl::OnDestroy()
{
	CXTRegistryManager regMgr;
	regMgr.WriteProfileInt(_T("FlowGraph"), _T("ComponentShowHeader"), IsHeaderVisible() ? 1 : 0);
	__super::OnDestroy();
}

#define ID_SORT_ASC  1
#define ID_SORT_DESC  2
#define ID_SHOWHIDE_HEADER 3

//////////////////////////////////////////////////////////////////////////
void CHyperGraphComponentsReportCtrl::OnRButtonDown(UINT nFlags, CPoint point) 
{
	CRect reportArea = GetReportRectangle();
	if (reportArea.PtInRect(point))
	{
		CPoint pt;
		GetCursorPos(&pt);

		CMenu menu;
		VERIFY(menu.CreatePopupMenu());
		// create main menu items
		CXTPReportColumns* pColumns = GetColumns();
		CXTPReportColumn* pCatColumn = pColumns->GetAt(1);

		// create main menu items
		menu.AppendMenu(MF_STRING, ID_SHOWHIDE_HEADER, IsHeaderVisible() ?  _T("Hide Header") : _T("Show Header"));

		// track menu
		int nMenuResult = CXTPCommandBars::TrackPopupMenu(&menu, TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTALIGN |TPM_RIGHTBUTTON, pt.x, pt.y, this, NULL);

		// other general items
		switch (nMenuResult)
		{
		case ID_SHOWHIDE_HEADER:
			SetHeaderVisible(!IsHeaderVisible());
			Populate();
			break;
		}
	}
	else
	{
		__super::OnRButtonDown(nFlags, point);
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphComponentsReportCtrl::OnReportColumnRClick( NMHDR* pNotifyStruct, LRESULT* result )
{
	XTP_NM_REPORTRECORDITEM* pItemNotify = (XTP_NM_REPORTRECORDITEM*) pNotifyStruct;
	ASSERT(pItemNotify->pColumn);
	CPoint ptClick = pItemNotify->pt;
	CXTPReportColumn* pColumn = pItemNotify->pColumn;

	CMenu menu;
	VERIFY(menu.CreatePopupMenu());

	CXTPReportColumns* pColumns = GetColumns();
	CXTPReportColumn* pNodeClassColumn = pColumns->GetAt(0);
	CXTPReportColumn* pCatColumn = pColumns->GetAt(1);

	// create main menu items
	menu.AppendMenu(MF_STRING, ID_SORT_ASC, _T("Sort ascending"));
	menu.AppendMenu(MF_STRING, ID_SORT_DESC, _T("Sort descending"));
	menu.AppendMenu(MF_STRING, ID_SHOWHIDE_HEADER, IsHeaderVisible() ?  _T("Hide Header") : _T("Show Header"));

	// track menu
	int nMenuResult = CXTPCommandBars::TrackPopupMenu(&menu, TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTALIGN |TPM_RIGHTBUTTON, ptClick.x, ptClick.y, this, NULL);

	// other general items
	switch (nMenuResult)
	{
	case ID_SORT_ASC:
	case ID_SORT_DESC:
		// only sort by node class
		if (pNodeClassColumn && pNodeClassColumn->IsSortable())
		{
			pColumns->SetSortColumn(pNodeClassColumn, nMenuResult == ID_SORT_ASC);
			Populate();
		}
		break;
	case ID_SHOWHIDE_HEADER:
		SetHeaderVisible(!IsHeaderVisible());
		Populate();
		break;
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphComponentsReportCtrl::OnLButtonDown( UINT nFlags, CPoint point )
{
	if (!m_bDragging) {
		__super::OnLButtonDown(nFlags,point);

		CRect reportArea = GetReportRectangle();
		if (reportArea.PtInRect(point))
		{
			CXTPReportRow* pRow = HitTest( point );
			if( pRow) 
			{
				if (pRow->GetParentRow() != 0)
				{
					m_ptDrag = point;
					m_bDragEx   = true;
				}
			}
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphComponentsReportCtrl::OnLButtonUp( UINT nFlags, CPoint point )
{
	m_bDragEx = false;

	if( !m_bDragging )
	{
		__super::OnLButtonUp(nFlags,point);
	}
	else
	{
		m_bDragging = false;
		ReleaseCapture();
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphComponentsReportCtrl::OnMouseMove( UINT nFlags, CPoint point )
{
	if (!m_bDragging)
	{
		__super::OnMouseMove(nFlags,point);

		const int dragX = ::GetSystemMetrics(SM_CXDRAG);
		const int dragY = ::GetSystemMetrics(SM_CYDRAG);
		if ( (m_ptDrag.x || m_ptDrag.y) && (abs(point.x - m_ptDrag.x) > dragX || abs(point.y - m_ptDrag.y) > dragY) )
		{
			CXTPReportRow* pRow = HitTest( m_ptDrag );
			if (pRow)
			{
				m_bDragging = true;
				SetCapture();
				point = m_ptDrag;
				ClientToScreen(&point);
				m_pDialog->OnComponentBeginDrag(pRow, point);
			}
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphComponentsReportCtrl::OnCaptureChanged( CWnd* pWnd)
{
	// Stop the dragging
	m_bDragging = false;
	m_bDragEx = false;
	m_ptDrag.SetPoint(0,0);
	__super::OnCaptureChanged(pWnd);
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphComponentsReportCtrl::OnReportItemDblClick( NMHDR* pNotifyStruct, LRESULT* result )
{
	XTP_NM_REPORTRECORDITEM* pItemNotify = (XTP_NM_REPORTRECORDITEM*) pNotifyStruct;
	CXTPReportRow* pRow = pItemNotify->pRow;
	if (pRow)
	{
		pRow->SetExpanded(pRow->IsExpanded() ? FALSE : TRUE);
	}
}

namespace
{
	struct NodeFilter
	{
	public:
		NodeFilter(uint32 mask) : mask(mask) {}
		bool Visit (CHyperNode* pNode)
		{
			if (pNode->IsEditorSpecialNode())
				return false;
			CFlowNode *pFlowNode = static_cast<CFlowNode*> (pNode);
			if ((pFlowNode->GetCategory() & mask) == 0)
				return false;
			return true;

			// Only if the usage mask is set check if fulfilled -> this is an exclusive thing
			if ((mask&EFLN_USAGE_MASK) != 0 && (pFlowNode->GetUsageFlags() & mask) == 0)
				return false;
			return true;
		}
		uint32 mask;
	};
};

class CComponentRecord : public CXTPReportRecord
{
public:
	CComponentRecord(bool bIsGroup=true, const CString& name="")
		: m_name(name), m_bIsGroup(bIsGroup)
	{
	}
	bool IsGroup() const { return m_bIsGroup; }
	const CString& GetName() const { return m_name; }
protected:
	CString m_name;
	bool m_bIsGroup;
};

//////////////////////////////////////////////////////////////////////////
void CHyperGraphComponentsReportCtrl::SetSearchKeyword(const CString& keyword)
{
	CString searchwords = keyword;
	searchwords.MakeLower();

	m_searchKeywords.clear();

	int pos = 0;
	do
	{
		CString search = searchwords.Tokenize( " ", pos );
		search.Trim();
		m_searchKeywords.push_back(search);		
	}
	while ( pos != -1 );

	Reload();
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphComponentsReportCtrl::Reload()
{
	std::map<CString,CComponentRecord*> groupMap;

	BeginUpdate();
	GetRecords()->RemoveAll();

	CFlowGraphManager *pMgr = GetIEditor()->GetFlowGraphManager();
	std::vector<_smart_ptr<CHyperNode> > prototypes;
	NodeFilter filter(m_mask);

	pMgr->GetPrototypesEx( prototypes, true, functor_ret(filter, &NodeFilter::Visit));
	for (int i = 0; i < prototypes.size(); i++)
	{
		const CHyperNode* pNode = prototypes[i];
		const CFlowNode* pFlowNode = static_cast<const CFlowNode*> (pNode);

		CString fullClassName = pFlowNode->GetUIClassName();

		// If search keyword is given,
		if (!m_searchKeywords.empty())
		{
			CString text = fullClassName;
			text.MakeLower();

			bool ok = true;
			for(size_t word = 0; word < m_searchKeywords.size(); ++word)
			{
				if(-1 == text.Find(m_searchKeywords[word]))
				{
					ok = false;
					break;
				}
			}

			if(!ok)
				continue;
		}

		CComponentRecord* pItemGroupRec = 0;
		int midPos = 0;
		int pos = 0;
		int len = fullClassName.GetLength();
		bool bUsePrototypeName = false; // use real prototype name or stripped from fullClassName

		CString nodeShortName;
		CString groupName = fullClassName.Tokenize( ":", pos);

		// check if a group name is given. if not, fake 'Misc:' group
		if (pos < 0 || pos >= len)
		{
			bUsePrototypeName = true; // re-fetch real prototype name
			fullClassName.Insert(0, "Misc:");
			pos = 0;
			len = fullClassName.GetLength();
			groupName = fullClassName.Tokenize( ":", pos);
		}

		CString pathName = ""; 
		while (pos >= 0 && pos < len)
		{
			pathName += groupName;
			pathName += ":";
			midPos = pos;

			CComponentRecord* pGroupRec = stl::find_in_map( groupMap,pathName,0 );
			if (pGroupRec == 0)
			{
				pGroupRec = new CComponentRecord();
				CXTPReportRecordItem* pNewItem = new CXTPReportRecordItemText(groupName);
				pNewItem->SetIconIndex(0);
				pGroupRec->AddItem(pNewItem);
				pGroupRec->AddItem(new CXTPReportRecordItemText(""));

				if (pItemGroupRec != 0)
				{
					pItemGroupRec->GetChilds()->Add(pGroupRec);
				}
				else
				{
					AddRecord(pGroupRec);
				}
				groupMap[pathName] = pGroupRec;
				pItemGroupRec = pGroupRec;
			}
			else
			{
				pItemGroupRec = pGroupRec;
			}

			// continue stripping 
			groupName = fullClassName.Tokenize(":", pos);
		};

		// short node name without ':'. used for display in last column
		nodeShortName = fullClassName.Mid(midPos);

		CComponentRecord* pRec = new CComponentRecord(false, pFlowNode->GetClassName());
		CXTPReportRecordItemText* pNewItem = new CXTPReportRecordItemText(nodeShortName);
		CXTPReportRecordItemText* pNewCatItem = new CXTPReportRecordItemText(pFlowNode->GetCategoryName());
		pNewItem->SetIconIndex(1);
		pRec->AddItem(pNewItem);
		pRec->AddItem(pNewCatItem);

		switch (pFlowNode->GetCategory())
		{
		case EFLN_APPROVED:
			//pNewItem->SetTextColor(RGB(20,200,20));
			//pNewCatItem->SetTextColor(RGB(20,200,20));
			//pNewItem->SetTextColor(RGB(120,120,124));
			//pNewCatItem->SetTextColor(RGB(120,120,124));
			pNewItem->SetTextColor(RGB(104,215,142));
			pNewCatItem->SetTextColor(RGB(104,215,142));
			break;
		case EFLN_ADVANCED:
			pNewItem->SetTextColor(RGB(104,162,255));
			pNewCatItem->SetTextColor(RGB(104,162,255));
			break;
		case EFLN_DEBUG:
			pNewItem->SetTextColor(RGB(220,180,20));
			pNewCatItem->SetTextColor(RGB(220,180,20));
			break;
		case EFLN_OBSOLETE:
			pNewItem->SetTextColor(RGB(255,0,0));
			pNewCatItem->SetTextColor(RGB(255,0,0));
			break;
		default:
			pNewItem->SetTextColor(RGB(0,0,0));
			pNewCatItem->SetTextColor(RGB(0,0,0));
			break;
		}

		assert (pItemGroupRec != 0);
		if (pItemGroupRec)
			pItemGroupRec->GetChilds()->Add(pRec);
		else
			AddRecord(pRec);
	}

	EndUpdate();
	Populate();
}

//////////////////////////////////////////////////////////////////////////
CImageList* CHyperGraphComponentsReportCtrl::CreateDragImage(CXTPReportRow* pRow)
{
	CXTPReportRecord* pRecord = pRow->GetRecord();
	if (pRecord == 0)
		return 0;

	CXTPReportRecordItem* pItem = pRecord->GetItem(0);
	if (pItem == 0)
		return 0;

	CXTPReportColumn* pCol = GetColumns()->GetAt(0);
	assert (pCol != 0);

	CClientDC	dc (this);
	CDC memDC;	
	if(!memDC.CreateCompatibleDC(&dc))
		return NULL;

	CRect rect;
	rect.SetRectEmpty();

	XTP_REPORTRECORDITEM_DRAWARGS drawArgs;
	drawArgs.pDC = &memDC;
	drawArgs.pControl = this;
	drawArgs.pRow = pRow;
	drawArgs.pColumn = pCol;
	drawArgs.pItem = pItem;
	drawArgs.rcItem = rect;
	XTP_REPORTRECORDITEM_METRICS metrics;
	pRow->GetItemMetrics(&drawArgs, &metrics);

	CString text = pItem->GetCaption(drawArgs.pColumn);

	CFont* pOldFont = memDC.SelectObject(GetFont());
	memDC.SelectObject(metrics.pFont);
	memDC.DrawText(text, &rect, DT_CALCRECT);

	HICON hIcon = m_imageList.ExtractIcon(pItem->GetIconIndex());
	int sx,sy;
	ImageList_GetIconSize(*&m_imageList, &sx, &sy);
	rect.right += sx+6;
	rect.bottom = sy > rect.bottom ? sy : rect.bottom;
	CRect boundingRect = rect;

	CBitmap bitmap;
	if(!bitmap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height()))
		return NULL;

	CBitmap* pOldMemDCBitmap = memDC.SelectObject( &bitmap );
	memDC.SetBkColor(	metrics.clrBackground);
	memDC.FillSolidRect(&rect, metrics.clrBackground);
	memDC.SetTextColor(GetPaintManager()->m_clrWindowText);

	::DrawIconEx (*&memDC, rect.left+2, rect.top, hIcon, sx, sy, 0, NULL, DI_NORMAL); 

	rect.left += sx+4;
	rect.top -= 1;
	memDC.DrawText(text, &rect, 0);
	memDC.SelectObject( pOldFont );
	memDC.SelectObject( pOldMemDCBitmap );

	// Create image list
	CImageList* pImageList = new CImageList;
	pImageList->Create(boundingRect.Width(), boundingRect.Height(), 
		ILC_COLOR | ILC_MASK , 0, 1);
	pImageList->Add(&bitmap, metrics.clrBackground); // Here green is used as mask color

	::DestroyIcon(hIcon);
	bitmap.DeleteObject();
	return pImageList;
}

//////////////////////////////////////////////////////////////////////////
class CHyperGraphViewClass : public TRefCountBase<IViewPaneClass>
{
	//////////////////////////////////////////////////////////////////////////
	// IClassDesc
	//////////////////////////////////////////////////////////////////////////
	virtual ESystemClassID SystemClassID() { return ESYSTEM_CLASS_VIEWPANE; };
	virtual REFGUID ClassID()
	{
		// {DE6E69F3-8B53-47de-89FF-11485852B6C9}
		static const GUID guid = { 0xde6e69f3, 0x8b53, 0x47de, { 0x89, 0xff, 0x11, 0x48, 0x58, 0x52, 0xb6, 0xc9 } };
		return guid;
	}
	virtual const char* ClassName() { return "Flow Graph"; };
	virtual const char* Category() { return "Game"; };
	//////////////////////////////////////////////////////////////////////////
	virtual CRuntimeClass* GetRuntimeClass() { return RUNTIME_CLASS(CHyperGraphDialog); };
	virtual const char* GetPaneTitle() { return _T("Flow Graph"); };
	virtual EDockingDirection GetDockingDirection() { return DOCK_FLOAT; };
	virtual CRect GetPaneRect() { return CRect(200,200,1000,800); };
	virtual bool SinglePane() { return false; };
	virtual bool WantIdleUpdate() { return true; };
};

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::RegisterViewClass()
{
	GetIEditor()->GetClassFactory()->RegisterClass( new CHyperGraphViewClass );
	GetIEditor()->GetSettingsManager()->AddToolName("FlowGraphLayout", "Flow Graph");
}

//////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CHyperGraphDialog,CXTPFrameWnd)

BEGIN_MESSAGE_MAP(CHyperGraphDialog, CXTPFrameWnd)
	ON_WM_SIZE()
	ON_WM_SETFOCUS()
	ON_WM_DESTROY()
	ON_WM_CLOSE()
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_COMMAND( ID_FILE_NEW,OnFileNew )
	ON_COMMAND( ID_FILE_OPEN,OnFileOpen )
	ON_COMMAND( ID_FILE_SAVE,OnFileSave )
	ON_COMMAND( ID_FILE_SAVE_AS,OnFileSaveAs )
	ON_COMMAND( ID_FILE_NEWACTION,OnFileNewAction )
	ON_COMMAND( ID_FILE_NEWUIACTION,OnFileNewUIAction )
	ON_COMMAND( ID_FILE_NEWMATERIALFXGRAPH,OnFileNewMatFXGraph )
	ON_COMMAND( ID_FILE_NEWFGMODULE_GLOBAL,OnFileNewGlobalFGModule )
	ON_COMMAND( ID_FILE_NEWFGMODULE_LEVEL,OnFileNewLevelFGModule )
	ON_COMMAND( ID_FILE_IMPORT,OnFileImport )
	ON_COMMAND( ID_FILE_EXPORTSELECTION,OnFileExportSelection )
	ON_COMMAND( ID_EDIT_FG_FIND, OnFind )
	ON_COMMAND( ID_FLOWGRAPH_PLAY,OnPlay )
	ON_COMMAND( ID_FLOWGRAPH_STOP,OnStop )
	ON_COMMAND( ID_FLOWGRAPH_DEBUG,OnToggleDebug )
	ON_COMMAND( ID_FLOWGRAPH_DEBUG_ERASE,OnEraseDebug )
	//ON_COMMAND( ID_FLOWGRAPH_PAUSE,OnPause )
	ON_COMMAND( ID_FLOWGRAPH_STEP,OnStep )
	ON_COMMAND( ID_TOOLS_EDITGRAPHTOKENS, OnEditGraphTokens )
	ON_COMMAND( ID_TOOLS_EDITMODULE, OnEditModuleInputsOutputs )
	ON_UPDATE_COMMAND_UI(ID_FLOWGRAPH_DEBUG, OnUpdateDebug)
	ON_UPDATE_COMMAND_UI(ID_FLOWGRAPH_PLAY, OnUpdatePlay)
	//ON_UPDATE_COMMAND_UI(ID_FLOWGRAPH_PAUSE, OnUpdateStep)
#ifdef _DEBUG
	ON_COMMAND_EX_RANGE( ID_COMPONENTS_APPROVED, ID_COMPONENTS_OBSOLETE, OnComponentsViewToggle)
	ON_UPDATE_COMMAND_UI_RANGE( ID_COMPONENTS_APPROVED, ID_COMPONENTS_OBSOLETE, OnComponentsViewUpdate)
#else
	ON_COMMAND_EX_RANGE( ID_COMPONENTS_APPROVED, ID_COMPONENTS_DEBUG, OnComponentsViewToggle)
	ON_UPDATE_COMMAND_UI_RANGE( ID_COMPONENTS_APPROVED, ID_COMPONENTS_DEBUG, OnComponentsViewUpdate)
#endif
	ON_COMMAND_EX(ID_VIEW_GRAPHS, OnToggleBar )
	ON_COMMAND_EX(ID_VIEW_NODEINPUTS, OnToggleBar )
	ON_COMMAND_EX(ID_VIEW_COMPONENTS, OnToggleBar )
	ON_COMMAND_EX(ID_VIEW_BREAKPOINTS, OnToggleBar )
	ON_COMMAND_EX(ID_VIEW_SEARCH, OnToggleBar )
	ON_COMMAND_EX(ID_VIEW_SEARCHRESULTS, OnToggleBar )
	ON_UPDATE_COMMAND_UI(ID_VIEW_GRAPHS, OnUpdateControlBar )
	ON_UPDATE_COMMAND_UI(ID_VIEW_NODEINPUTS, OnUpdateControlBar )
	ON_UPDATE_COMMAND_UI(ID_VIEW_COMPONENTS, OnUpdateControlBar )
	ON_UPDATE_COMMAND_UI(ID_VIEW_BREAKPOINTS, OnUpdateControlBar )
	ON_UPDATE_COMMAND_UI(ID_VIEW_SEARCH, OnUpdateControlBar )
	ON_UPDATE_COMMAND_UI(ID_VIEW_SEARCHRESULTS, OnUpdateControlBar )

	ON_COMMAND_EX(ID_VIEW_MULTIPLAYER, OnMultiPlayerViewToggle)
	ON_UPDATE_COMMAND_UI(ID_VIEW_MULTIPLAYER, OnMultiPlayerViewUpdate)

	ON_NOTIFY(TVN_SELCHANGED, IDC_HYPERGRAPH_GRAPHS, OnGraphsSelChanged)
	ON_NOTIFY(NM_RCLICK, IDC_HYPERGRAPH_GRAPHS, OnGraphsRightClick)
	ON_NOTIFY(NM_RCLICK, IDC_BREAKPOINTS, OnBreakpointsRightClick)
	ON_NOTIFY(NM_CLICK, IDC_BREAKPOINTS, OnBreakpointsClick)
	ON_NOTIFY(NM_DBLCLK, IDC_HYPERGRAPH_GRAPHS, OnGraphsDblClick)

	ON_NOTIFY(XTP_LBN_SELCHANGE, ID_FG_BACK, OnNavListBoxControlSelChange)
	ON_NOTIFY(XTP_LBN_SELCHANGE, ID_FG_FORWARD, OnNavListBoxControlSelChange)
	ON_NOTIFY(XTP_LBN_POPUP, ID_FG_BACK, OnNavListBoxControlPopup)
	ON_NOTIFY(XTP_LBN_POPUP, ID_FG_FORWARD, OnNavListBoxControlPopup)
	ON_UPDATE_COMMAND_UI(ID_FG_BACK,    OnUpdateNav)
	ON_UPDATE_COMMAND_UI(ID_FG_FORWARD, OnUpdateNav)
	ON_COMMAND( ID_FG_FORWARD,OnNavForward )
	ON_COMMAND( ID_FG_BACK,OnNavBack )
	
	ON_COMMAND(ID_TOOLS_CUSTOMIZEKEYBOARD, OnCustomize)
	ON_COMMAND(ID_TOOLS_EXPORT_SHORTCUTS, OnExportShortcuts)
	ON_COMMAND(ID_TOOLS_IMPORT_SHORTCUTS, OnImportShortcuts)
	ON_EN_CHANGE( IDC_COMPONENT_SEARCH,OnComponentSearchEditChange )

	//////////////////////////////////////////////////////////////////////////
	// XT Commands.
	ON_MESSAGE(XTPWM_DOCKINGPANE_NOTIFY, OnDockingPaneNotify)
	ON_XTP_CREATECOMMANDBAR()
	ON_XTP_CREATECONTROL()
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
CHyperGraphDialog::CHyperGraphDialog()
{
	GetIEditor()->RegisterNotifyListener( this );
	GetIEditor()->GetFlowGraphManager()->AddListener(this);

	m_pPropertiesItem = 0;
	m_pPropertiesFolder = NULL;
	m_pDragImage = NULL;
	m_pSearchResultsCtrl = 0;
	m_pSearchOptionsView = 0;
	m_pGraphProperties = 0;
	m_pGraphTokens = 0;
	m_pNavGraph = 0;
	m_pFlowGraphDebugger = GetIFlowGraphDebuggerPtr();

	WNDCLASS wndcls;
	HINSTANCE hInst = AfxGetInstanceHandle();
	if (!(::GetClassInfo(hInst, HYPERGRAPH_DIALOGFRAME_CLASSNAME, &wndcls)))
	{
		// otherwise we need to register a new class
		wndcls.style            = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
		wndcls.lpfnWndProc      = ::DefWindowProc;
		wndcls.cbClsExtra       = wndcls.cbWndExtra = 0;
		wndcls.hInstance        = hInst;
		wndcls.hIcon            = NULL;
		wndcls.hCursor          = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
		wndcls.hbrBackground    = (HBRUSH) (COLOR_3DFACE + 1);
		wndcls.lpszMenuName     = NULL;
		wndcls.lpszClassName    = HYPERGRAPH_DIALOGFRAME_CLASSNAME;
		if (!AfxRegisterClass(&wndcls))
		{
			AfxThrowResourceException();
		}
	}
	CRect rc(0,0,0,0);
	BOOL bRes = Create( WS_CHILD,rc,AfxGetMainWnd() );
	if (!bRes)
		return;
	ASSERT( bRes );

	OnInitDialog();
}

//////////////////////////////////////////////////////////////////////////
CHyperGraphDialog::~CHyperGraphDialog()
{
	SAFE_DELETE (m_pSearchResultsCtrl);
	SAFE_DELETE (m_pSearchOptionsView);
	SAFE_DELETE (m_pGraphProperties);
	SAFE_DELETE (m_pGraphTokens);

	if (GetIEditor()->GetFlowGraphManager())
		GetIEditor()->GetFlowGraphManager()->RemoveListener(this);

	GetIEditor()->UnregisterNotifyListener( this );
}

//////////////////////////////////////////////////////////////////////////
BOOL CHyperGraphDialog::Create( DWORD dwStyle,const RECT& rect,CWnd* pParentWnd )
{
	return __super::Create( HYPERGRAPH_DIALOGFRAME_CLASSNAME,NULL,dwStyle,rect,pParentWnd );
}

//////////////////////////////////////////////////////////////////////////
BOOL CHyperGraphDialog::OnCmdMsg(UINT nID, int nCode, void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo)
{
	BOOL res = FALSE;
	if (m_view.m_hWnd)
	{
		res = m_view.OnCmdMsg(nID,nCode,pExtra,pHandlerInfo);
		if (TRUE == res)
			return res;
	}

	/*
	CPushRoutingFrame push(this);
	return CWnd::OnCmdMsg(nID,nCode,pExtra,pHandlerInfo);
	*/

	return __super::OnCmdMsg(nID,nCode,pExtra,pHandlerInfo);
}

//////////////////////////////////////////////////////////////////////////
BOOL CHyperGraphDialog::OnInitDialog()
{
	ModifyStyleEx( WS_EX_CLIENTEDGE, 0 );

	CRect rc;
	GetClientRect( &rc );

	try
	{
		//////////////////////////////////////////////////////////////////////////
		// Initialize the command bars
		if (!InitCommandBars())
			return -1;

	}	catch (CResourceException *e)
	{
		e->Delete();
		return -1;
	}

	// Get a pointer to the command bars object.
	CXTPCommandBars* pCommandBars = GetCommandBars();
	if(pCommandBars == NULL)
	{
		TRACE0("Failed to create command bars object.\n");
		return -1;      // fail to create
	}

	CMFCUtils::LoadShortcuts(pCommandBars, IDR_HYPERGRAPH, "FlowGraph");

	// Add the menu bar
	CXTPCommandBar* pMenuBar = pCommandBars->SetMenu( _T("Menu Bar"),IDR_HYPERGRAPH );
	ASSERT(pMenuBar);
	pMenuBar->SetFlags(xtpFlagStretched);
	pMenuBar->EnableCustomization(TRUE);

	//////////////////////////////////////////////////////////////////////////
	// Create standart toolbar.
	CXTPToolBar *pStdToolBar = pCommandBars->Add( _T("HyperGraph ToolBar"),xtpBarTop );
	VERIFY(pStdToolBar->LoadToolBar(IDR_FLOWGRAPH_BAR));
	//////////////////////////////////////////////////////////////////////////

	//m_cDlgToolBar.SetButtonStyle( m_cDlgToolBar.CommandToIndex(ID_TV_ADDKEY),TBBS_CHECKGROUP );

	//////////////////////////////////////////////////////////////////////////
	GetDockingPaneManager()->InstallDockingPanes(this);
	GetDockingPaneManager()->SetTheme(xtpPaneThemeOffice2003);
	GetDockingPaneManager()->SetThemedFloatingFrames(TRUE);
	if (CMainFrame::GetDockingHelpers())
	{
		GetDockingPaneManager()->SetAlphaDockingContext(TRUE);
		GetDockingPaneManager()->SetShowDockingContextStickers(TRUE);
	}
	//////////////////////////////////////////////////////////////////////////

	CFlowGraphSearchOptions::GetSearchOptions()->Serialize(true);

	CXTRegistryManager regMgr;

	// FIXME: Platform independent uint32 -> dword ...
	DWORD compView;
	if (regMgr.GetProfileDword(_T("FlowGraph"), _T("ComponentView"), &compView) == false)
		compView = EFLN_APPROVED | EFLN_ADVANCED | EFLN_DEBUG;
	m_componentsViewMask = compView;
	m_componentsReportCtrl.SetComponentFilterMask(m_componentsViewMask);
	m_view.SetComponentViewMask(m_componentsViewMask);

	// Right pane needs to be created before left pane since left pane will receive window events right after creation
	// and some of the event handler ( OnGraphsSelChanged ) access objects that are created in CreateRightPane
	CreateRightPane();
	CreateLeftPane();
	UpdateComponentPaneTitle();

	// Create View.
	m_view.Create( WS_CHILD|WS_CLIPCHILDREN|WS_VISIBLE,rc,this,AFX_IDW_PANE_FIRST );

	int paneLayoutVersion = regMgr.GetProfileInt(_T("FlowGraph"), _T("FlowGraphLayoutVersion"), 0);
	if (paneLayoutVersion == FlowGraphLayoutVersion)
	{
		CXTPDockingPaneLayout layout(GetDockingPaneManager());
		if (layout.Load(_T("FlowGraphLayout"))) 
		{
			if (layout.GetPaneList().GetCount() > 0)
				GetDockingPaneManager()->SetLayout(&layout);	
		}
	}
	else
	{
		regMgr.WriteProfileInt(_T("FlowGraph"), _T("FlowGraphLayoutVersion"), FlowGraphLayoutVersion);
	}

	m_statusBar.Create(this);
	static UINT indicators[] = 
	{
		1,
	};
	m_statusBar.SetIndicators( indicators, sizeof(indicators)/sizeof(*indicators) );
	m_statusBar.SetPaneInfo(0,1, SBPS_STRETCH, 100);
	m_statusBar.ShowWindow(SW_HIDE);
	UpdateTitle(0);

	return TRUE;
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::PostNcDestroy()
{
	delete this;
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::DoDataExchange(CDataExchange* pDX)
{
	__super::DoDataExchange(pDX);
}

//////////////////////////////////////////////////////////////////////////
BOOL CHyperGraphDialog::PreTranslateMessage(MSG* pMsg)
{
	bool bFramePreTranslate = true;
	if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
	{
		CWnd* pWnd = CWnd::GetFocus();
		if (pWnd && pWnd->IsKindOf(RUNTIME_CLASS(CEdit)))
			bFramePreTranslate = false;
	}

	if (bFramePreTranslate)
	{
		// allow tooltip messages to be filtered
		if (__super::PreTranslateMessage(pMsg))
			return TRUE;
	}

	if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
	{
		// All keypresses are translated by this frame window

		::TranslateMessage(pMsg);
		::DispatchMessage(pMsg);

		return TRUE;
	}

	return FALSE;
}


//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
BOOL CHyperGraphDialog::OnEraseBkgnd(CDC* pDC) 
{
	return TRUE;
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnPaint()
{
	CPaintDC PaintDC(this); // device context for painting
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnSize(UINT nType, int cx, int cy)
{
	__super::OnSize(nType, cx, cy);

	/*
	if (m_view.m_hWnd)
	{
	CRect rc;
	GetClientRect( &rc );

	rc.right -= 300;
	m_view.MoveWindow( rc );
	m_view.ShowWindow(SW_SHOW);
	}
	*/

	//	RecalcLayout();

	/*
	if (m_wndSplitter.GetSafeHwnd())
	{
	CRect rc;
	GetClientRect(&rc);
	m_wndSplitter.MoveWindow(&rc,FALSE);
	}
	RecalcLayout();
	*/
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnSetFocus(CWnd* pOldWnd)
{
	__super::OnSetFocus(pOldWnd);
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnDestroy()
{
	CXTPDockingPaneLayout layout(GetDockingPaneManager());
	GetDockingPaneManager()->GetLayout( &layout );
	layout.Save(_T("FlowGraphLayout"));
	CFlowGraphSearchOptions::GetSearchOptions()->Serialize(false);
	CXTRegistryManager regMgr;
	DWORD mask = m_componentsViewMask;
	regMgr.WriteProfileDword(_T("FlowGraph"), _T("ComponentView"), &mask);

	ClearGraph();
	__super::OnDestroy();
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnClose()
{
	__super::OnClose();
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::CreateRightPane()
{
	CRect rc(0,0,220,500);
	CXTPDockingPane* pDockPane = GetDockingPaneManager()->CreatePane( IDW_HYPERGRAPH_RIGHT_PANE,rc,dockRightOf);
	pDockPane->SetTitle( _T("Inputs") );

	m_wndTaskPanel.Create( WS_CHILD,rc,this,0 );

	m_wndTaskPanel.SetBehaviour(xtpTaskPanelBehaviourExplorer);
	//m_wndTaskPanel.SetBehaviour(xtpTaskPanelBehaviourList);
	//SetTheme(xtpTaskPanelThemeListViewOffice2003);
	//SetTheme(xtpTaskPanelThemeToolboxWhidbey);
	m_wndTaskPanel.SetTheme(xtpTaskPanelThemeNativeWinXP);
	m_wndTaskPanel.SetHotTrackStyle(xtpTaskPanelHighlightItem);
	m_wndTaskPanel.SetSelectItemOnFocus(TRUE);
	m_wndTaskPanel.AllowDrag(FALSE);

	m_wndTaskPanel.SetAnimation( xtpTaskPanelAnimationNo );

	m_wndTaskPanel.GetPaintManager()->m_rcGroupOuterMargins.SetRect(0,0,0,0);
	m_wndTaskPanel.GetPaintManager()->m_rcGroupInnerMargins.SetRect(0,0,0,0);
	m_wndTaskPanel.GetPaintManager()->m_rcItemOuterMargins.SetRect(0,0,0,0);
	m_wndTaskPanel.GetPaintManager()->m_rcItemInnerMargins.SetRect(1,1,1,1);
	m_wndTaskPanel.GetPaintManager()->m_rcControlMargins.SetRect(2,0,2,0);
	m_wndTaskPanel.GetPaintManager()->m_nGroupSpacing = 0;

	//////////////////////////////////////////////////////////////////////////
	// Create properties control.
	//////////////////////////////////////////////////////////////////////////
	m_wndProps.Create( WS_CHILD,rc,&m_wndTaskPanel );

	//m_wndProps.SetFlags( CPropertyCtrl::F_VS_DOT_NET_STYLE );
	m_wndProps.SetItemHeight( 16 );
	m_wndProps.ExpandAll();

	m_view.SetPropertyCtrl( &m_wndProps );
	//////////////////////////////////////////////////////////////////////////

	m_pPropertiesFolder = m_wndTaskPanel.AddGroup(ID_PROPERTY_GROUP);
	m_pPropertiesFolder->SetCaption( "Inputs" );
	m_pPropertiesFolder->SetItemLayout(xtpTaskItemLayoutDefault);

	m_pPropertiesItem =  m_pPropertiesFolder->AddControlItem(m_wndProps.GetSafeHwnd());
	m_pPropertiesItem->SetCaption( "Properties" );

	m_wndTaskPanel.ExpandGroup( m_pPropertiesFolder,FALSE );

	CXTPTaskPanelItem *pItem = 0;
	CXTPTaskPanelGroup *pNodeGroup = m_wndTaskPanel.AddGroup(ID_NODE_INFO_GROUP);
	pNodeGroup->SetCaption( "Selected Node Info" );

	pItem = pNodeGroup->AddLinkItem(ID_NODE_INFO);
	pItem->SetType(xtpTaskItemTypeText);

	m_pGraphProperties = new CFlowGraphProperties(this, &m_wndTaskPanel);
	m_pGraphProperties->Create(WS_CHILD|WS_BORDER,CRect(0,0,0,0),this,ID_GRAPH_INFO_GROUP);

	m_pGraphTokens = new CFlowGraphTokensCtrl(this, &m_wndTaskPanel);
	m_pGraphTokens->Create(WS_CHILD|WS_BORDER, CRect(0,0,0,0), this, ID_VARIABLES_GROUP);

	CXTPDockingPane* pSearchPane = GetDockingPaneManager()->CreatePane( IDW_HYPERGRAPH_SEARCH_PANE,CRect(0,0,200,250),dockBottomOf,pDockPane );
	pSearchPane->SetTitle( _T("Search") );
	m_pSearchOptionsView = new CFlowGraphSearchCtrl(this);

	CXTPDockingPane* pSearchResultsPane = GetDockingPaneManager()->CreatePane( IDW_HYPERGRAPH_SEARCHRESULTS_PANE,rc,dockBottomOf,pSearchPane );
	pSearchResultsPane->SetTitle( _T("SearchResults") );
	//pSearchResultsPane->SetMinTrackSize(CSize(100,50));

	CXTPDockingPane* pBreakpoints = GetDockingPaneManager()->CreatePane( IDW_HYPERGRAPH_BREAKPOINTS_PANE,rc,dockBottomOf,pSearchResultsPane );
	pBreakpoints->SetTitle( _T("Breakpoints") );

	m_breakpointsTreeCtrl.Create( WS_CHILD|WS_TABSTOP,rc,this,IDC_BREAKPOINTS );

	m_pSearchResultsCtrl = new CFlowGraphSearchResultsCtrl(this);
	m_pSearchResultsCtrl->Create( WS_CHILD|WS_BORDER,CRect(0,0,0,0),this,0 );
	m_pSearchResultsCtrl->SetOwner(this);

	// set the results control for the search control
	m_pSearchOptionsView->SetResultsCtrl(m_pSearchResultsCtrl);
	m_pSearchOptionsView->SetOwner(this);
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::CreateLeftPane()
{
	CRect rc(0,0,220,300);
	m_componentsTaskPanel.Create( WS_CHILD,rc,this,0 );
	m_componentsTaskPanel.SetBehaviour(xtpTaskPanelBehaviourExplorer);
	m_componentsTaskPanel.SetTheme(xtpTaskPanelThemeNativeWinXP);
	m_componentsTaskPanel.SetHotTrackStyle(xtpTaskPanelHighlightItem);
	m_componentsTaskPanel.SetSelectItemOnFocus(TRUE);
	m_componentsTaskPanel.AllowDrag(FALSE);
	m_componentsTaskPanel.SetAnimation( xtpTaskPanelAnimationNo );
	m_componentsTaskPanel.GetPaintManager()->m_rcGroupOuterMargins.SetRect(0,0,0,0);
	m_componentsTaskPanel.GetPaintManager()->m_rcGroupInnerMargins.SetRect(0,0,0,0);
	m_componentsTaskPanel.GetPaintManager()->m_rcItemOuterMargins.SetRect(0,0,0,0);
	m_componentsTaskPanel.GetPaintManager()->m_rcItemInnerMargins.SetRect(1,1,1,1);
	m_componentsTaskPanel.GetPaintManager()->m_rcControlMargins.SetRect(2,0,2,0);
	m_componentsTaskPanel.GetPaintManager()->m_nGroupSpacing = 0;

	CXTPTaskPanelGroup *pNodeGroup = m_componentsTaskPanel.AddGroup(ID_COMPONENTS_GROUP);
	pNodeGroup->ShowCaption(FALSE);
	pNodeGroup->AddTextItem(_T("Search keyword:"));
	m_componentSearchEdit.Create( WS_CHILD|WS_VISIBLE|WS_BORDER|ES_MULTILINE,CRect(0,0,90,20),this, IDC_COMPONENT_SEARCH);
	m_componentSearchEdit.SetFont( CFont::FromHandle((HFONT)gSettings.gui.hSystemFont) );
	m_componentSearchEdit.SetParent(&m_componentsTaskPanel);
	pNodeGroup->AddControlItem(m_componentSearchEdit.GetSafeHwnd());

	pNodeGroup->AddTextItem(_T("Components:"));
	m_componentsReportCtrl.Create(WS_CHILD|WS_TABSTOP,CRect(0,0,100,800),this,IDC_HYPERGRAPH_COMPONENTS );
	m_componentsReportCtrl.SetDialog(this);
	m_componentsReportCtrl.SetParent(&m_componentsTaskPanel);
	m_componentsReportCtrl.Reload();
	pNodeGroup->AddControlItem(m_componentsReportCtrl.GetSafeHwnd());

	CXTPDockingPane* pComponentsPane = GetDockingPaneManager()->CreatePane( IDW_HYPERGRAPH_COMPONENTS_PANE,rc,dockLeftOf );
	pComponentsPane->SetTitle( _T("Components") );

	m_graphsTreeCtrl.Create( WS_CHILD|WS_TABSTOP,rc,this,IDC_HYPERGRAPH_GRAPHS );
	m_graphsTreeCtrl.EnableMultiSelect(TRUE);
	m_graphsTreeCtrl.Reload();

	CXTPDockingPane* pGraphsPane = GetDockingPaneManager()->CreatePane( IDW_HYPERGRAPH_TREE_PANE,rc,dockBottomOf,pComponentsPane );
	pGraphsPane->SetTitle( _T("Flow Graphs") );
}

/////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnViewSelectionChange()
{
	if (!m_pPropertiesItem)
		return;

	m_wndTaskPanel.ExpandGroup( m_pPropertiesFolder,FALSE );

	CRect rc;
	m_wndTaskPanel.GetClientRect(rc);
	// Resize to fit properties.
	int h = m_wndProps.GetVisibleHeight();
	m_wndProps.SetWindowPos( NULL,0,0,rc.right,h + 1,SWP_NOMOVE );

	m_wndProps.GetClientRect(rc);

	::GetClientRect(m_wndProps.GetSafeHwnd(), rc);

	m_pPropertiesItem->SetControlHandle( m_wndProps.GetSafeHwnd() );
	m_wndTaskPanel.Reposition(FALSE);

	m_wndTaskPanel.ExpandGroup( m_pPropertiesFolder,TRUE );

	//////////////////////////////////////////////////////////////////////////
	std::vector<CHyperNode*> nodes;
	m_view.GetSelectedNodes(nodes);
	if (nodes.size() <= 1)
	{
		CXTPTaskPanelGroupItem* pItem = 0;
		CXTPTaskPanelGroup *pGroup = m_wndTaskPanel.FindGroup(ID_NODE_INFO_GROUP);
		CXTPTaskPanelGroup *pGroupDescription = m_wndTaskPanel.FindGroup(ID_GRAPH_INFO_GROUP);
		
		if(pGroupDescription)
		{
			if(nodes.size() > 0)
			{
				CHyperNode *pNode = nodes[0];
				if(pNode)
				{
					m_pGraphProperties->SetDescription(pNode->GetDescription());
				}
				else
				{
					m_pGraphProperties->SetDescription("");
				}
			}
			else
			{
				m_pGraphProperties->SetDescription("");
			}
		}

		if (pGroup)
		{
			pItem = pGroup->FindItem(ID_NODE_INFO);
		}
		if (pItem)
		{
			if (nodes.size() == 1) {
				CString nodeInfo;
				CHyperNode *pNode = nodes[0];
				if (pNode->IsEditorSpecialNode())
				{
					nodeInfo.Format( "Name: %s\nClass: %s\n",
						pNode->GetName(),pNode->GetClassName() );
				}
				else
				{	
					CFlowNode *pFlowNode = static_cast<CFlowNode*> (pNode);
					CString cat = pFlowNode->GetCategoryName();
					const uint32 usageFlags = pFlowNode->GetUsageFlags();
					// TODO: something with Usage flags
					if (gSettings.bFlowGraphShowNodeIDs)
						nodeInfo.Format( "Name: %s\nClass: %s\nNodeID=%d\nCategory: %s\n",
						pFlowNode->GetName(),pFlowNode->GetClassName(),pFlowNode->GetId(),cat.GetString());
					else
						nodeInfo.Format( "Name: %s\nClass: %s\nCategory: %s\n",
						pFlowNode->GetName(),pFlowNode->GetClassName(),cat.GetString() );
				}
				pItem->SetCaption( nodeInfo );
			} else {
				pItem->SetCaption("");
			}
		}
	}
	else
	{
		//m_wndTaskPanel.GetGroups()->De
		//m_wndTaskPanel.GetGroups()->Remove( m_wndTaskPanel.FindGroup(ID_NODE_INFO_GROUP) );
	}
}

//////////////////////////////////////////////////////////////////////////
LRESULT CHyperGraphDialog::OnDockingPaneNotify(WPARAM wParam, LPARAM lParam)
{
	if (wParam == XTP_DPN_SHOWWINDOW)
	{
		// get a pointer to the docking pane being shown.
		CXTPDockingPane* pwndDockWindow = (CXTPDockingPane*)lParam;
		if (!pwndDockWindow->IsValid())
		{
			switch (pwndDockWindow->GetID())
			{
			case IDW_HYPERGRAPH_RIGHT_PANE:
				pwndDockWindow->Attach(&m_wndTaskPanel);
				m_wndTaskPanel.ShowWindow(SW_SHOW);
				break;
			case IDW_HYPERGRAPH_TREE_PANE:
				pwndDockWindow->Attach(&m_graphsTreeCtrl);
				m_graphsTreeCtrl.ShowWindow(SW_SHOW);
				break;
			case IDW_HYPERGRAPH_COMPONENTS_PANE:
				pwndDockWindow->Attach(&m_componentsTaskPanel);
				m_componentsTaskPanel.ShowWindow(SW_SHOW);
				break;
			case IDW_HYPERGRAPH_SEARCH_PANE:
				pwndDockWindow->Attach(m_pSearchOptionsView);
				m_pSearchOptionsView->ShowWindow(SW_SHOW);
				break;
			case IDW_HYPERGRAPH_SEARCHRESULTS_PANE:
				pwndDockWindow->Attach(m_pSearchResultsCtrl);
				m_pSearchResultsCtrl->ShowWindow(SW_SHOW);
				break;
			case IDW_HYPERGRAPH_BREAKPOINTS_PANE:
				pwndDockWindow->Attach(&m_breakpointsTreeCtrl);
				m_breakpointsTreeCtrl.ShowWindow(SW_SHOW);
				break;
			default:
				return FALSE;
			}
		}
		return TRUE;
	}
	else if (wParam == XTP_DPN_CLOSEPANE)
	{
		// get a pointer to the docking pane being shown.
		CXTPDockingPane* pwndDockWindow = (CXTPDockingPane*)lParam;
		if (pwndDockWindow->IsValid())
		{
			switch (pwndDockWindow->GetID())
			{
			case IDW_HYPERGRAPH_RIGHT_PANE:
				break;
			}
		}
	}

	return FALSE;
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::SetGraph( CHyperGraph *pGraph )
{
	// CryLogAlways("CHyperGraphDialog::SetGraph: Switching to 0x%p", pGraph);
	m_view.SetGraph( pGraph );
	m_graphsTreeCtrl.SetCurrentGraph( pGraph );
	if(m_pGraphProperties)
	{
		m_pGraphProperties->SetGraph ( pGraph );
	}
	if(m_pGraphTokens)
	{
		m_pGraphTokens->SetGraph(pGraph);
	}

	UpdateTitle(pGraph);

	if (pGraph != 0)
	{
		/* If we want to show the title somewhere
		CString name, groupName;
		GetPrettyName(pGraph, name, groupName);
		title += groupName;
		title += ":";
		title += name;
		*/

		std::list<CHyperGraph*>::iterator iter = std::find(m_graphList.begin(), m_graphList.end(), pGraph);
		if (iter != m_graphList.end())
		{
			m_graphIterCur = iter;
		}
		else
		{
			// maximum entry 20
			while (m_graphList.size() > 20)
			{
				m_graphList.pop_front();
			}
			m_graphIterCur = m_graphList.insert(m_graphList.end(), pGraph);
		}
	}
	else
		m_graphIterCur = m_graphList.end();
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::NewGraph()
{
	CHyperGraph* pGraph = static_cast<CHyperGraph*>(GetIEditor()->GetFlowGraphManager()->CreateGraph());
	
	if(pGraph)
		pGraph->AddRef();
		
	SetGraph(pGraph);
}


//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnFileNew()
{
	ClearGraph();
	// Make a new graph.
	NewGraph();
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnFileOpen()
{
	ClearGraph();
	CString filename;
	// if (CFileUtil::SelectSingleFile( EFILE_TYPE_ANY,filename,GRAPH_FILE_FILTER )) // game dialog
	if (CFileUtil::SelectFile ( GRAPH_FILE_FILTER, "", filename )) // native dialog
	{
		NewGraph();
		bool ok = m_view.GetGraph()->Load( filename );
		if (!ok)
		{
			Warning ("Cannot load FlowGraph from file '%s'.\nMake sure the file is actually a FlowGraph XML File.", filename.GetString());
		}
		if(m_view.GetGraph())
			m_view.GetGraph()->SetName(Path::GetFileName(filename));
		m_graphsTreeCtrl.Reload();
		m_view.InvalidateView(true);
		m_view.FitFlowGraphToView();
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnFileSave()
{
	CHyperGraph *pGraph = m_view.GetGraph();
	if (!pGraph)
		return;

	CString filename = pGraph->GetFilename();
	Path::ReplaceExtension(filename, ".xml");
	if (filename.IsEmpty())
	{
		OnFileSaveAs();
	}
	else
	{
		bool ok = false;

		assert(pGraph->IsFlowGraph());	
		if(pGraph->IsFlowGraph())
		{
			CFlowGraph* pFlowGraph = static_cast<CFlowGraph*>(pGraph);
			if(pFlowGraph->GetIFlowGraph()->GetType() == IFlowGraph::eFGT_Module)
			{
				GetIEditor()->GetFlowGraphModuleManager()->SaveModuleGraph(pFlowGraph);
				ok = true;
			}
			else
			{
					ok = pGraph->Save(filename);
			}
		}
		
		if (!ok)
		{
			Warning ("Cannot save FlowGraph to file '%s'.\nMake sure the path is correct.", filename.GetString());
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnFileSaveAs()
{
	CHyperGraph *pGraph = m_view.GetGraph();
	if (!pGraph)
		return;

	CString filename = CString(pGraph->GetName()) + ".xml";
	CString dir = Path::GetPath(pGraph->GetFilename());
	if (CFileUtil::SelectSaveFile( GRAPH_FILE_FILTER,"xml",dir,filename ))
	{
		CWaitCursor wait;

		bool ok = false;
		assert(pGraph->IsFlowGraph());
		if(pGraph->IsFlowGraph())
		{
			CFlowGraph* pFlowGraph = static_cast<CFlowGraph*>(pGraph);
			if(pFlowGraph->GetIFlowGraph()->GetType() == IFlowGraph::eFGT_Module)
			{	
				GetIEditor()->GetFlowGraphModuleManager()->SaveModuleGraph(pFlowGraph);
				ok = true;
			}
			else
			{
					ok = pGraph->Save(filename);
			}
		}
		
		if (!ok)
		{
			Warning ("Cannot save FlowGraph to file '%s'.\nMake sure the path is correct.", filename.GetString());
		}
	}
}

void CHyperGraphDialog::OnFileNewGlobalFGModule()
{
	NewFGModule();
}

void CHyperGraphDialog::OnFileNewLevelFGModule()
{
	if (GetIEditor()->GetGameEngine()->IsLevelLoaded())
	{
		NewFGModule(false);
	}
}

void CHyperGraphDialog::NewFGModule(bool bGlobal/*=true*/)
{
	CString filename;
	CEditorFlowGraphModuleManager* pModuleManager = GetIEditor()->GetFlowGraphModuleManager();

	if(pModuleManager == NULL)
		return;

	if(pModuleManager->NewModule(filename, bGlobal))
	{
		IFlowGraphPtr pModuleGraph = pModuleManager->GetModuleFlowGraph(PathUtil::GetFileName(filename.GetString()));

		if (pModuleGraph)
		{
			CFlowGraphManager* pManager = GetIEditor()->GetFlowGraphManager();
			CFlowGraph* pFlowGraph = pManager->FindGraph( pModuleGraph );
			assert( pFlowGraph );
			if ( pFlowGraph )
			{
				pFlowGraph->GetIFlowGraph()->SetType(IFlowGraph::eFGT_Module);
				pManager->OpenView( pFlowGraph );
				m_componentsReportCtrl.Reload();
			}
		}
		else
			SetGraph( NULL );
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnFileNewAction()
{
	CString filename;
	if ( GetIEditor()->GetAI()->NewAction(filename) )
	{
		IAIAction* pAction = gEnv->pAISystem->GetAIActionManager()->GetAIAction( PathUtil::GetFileName(filename.GetString()) );
		if ( pAction )
		{
			CFlowGraphManager* pManager = GetIEditor()->GetFlowGraphManager();
			CFlowGraph* pFlowGraph = pManager->FindGraphForAction( pAction );
			assert( pFlowGraph );
			if ( pFlowGraph )
			{
				pFlowGraph->GetIFlowGraph()->SetType(IFlowGraph::eFGT_AIAction);
				pManager->OpenView( pFlowGraph );
			}
		}
		else
			SetGraph( NULL );
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnEditGraphTokens()
{
	if(CHyperGraph* pGraph = m_view.GetGraph())
	{
		if(pGraph->IsFlowGraph())
		{
			CFlowGraph* pFlowGraph = (CFlowGraph*)pGraph;
			IFlowGraph* pIFlowGraph = pFlowGraph->GetIFlowGraph();
			if(pIFlowGraph)
			{
				// get latest tokens from graph
				size_t tokenCount = pIFlowGraph->GetGraphTokenCount();
				TTokens newTokens;
				for(size_t i=0; i<tokenCount; ++i)
				{
					const IFlowGraph::SGraphToken* graphToken = pIFlowGraph->GetGraphToken(i);
					STokenData newToken;
					newToken.name = graphToken->name.c_str();
					newToken.type = graphToken->type;
					newTokens.push_back(newToken);
				}

				CFlowGraphTokensDlg dlg(this);
				dlg.SetTokenData(newTokens);
				dlg.DoModal();

				// get token list from dialog, set on graph
				TTokens tokens = dlg.GetTokenData();

				pIFlowGraph->RemoveGraphTokens();

				for(size_t i=0; i<tokens.size(); ++i)
				{
					IFlowGraph::SGraphToken graphToken;
					graphToken.name = tokens[i].name.GetBuffer();
					graphToken.type = tokens[i].type;

					pIFlowGraph->AddGraphToken(graphToken);
				}

				m_pGraphTokens->UpdateGraphProperties(pGraph);
			}
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnEditModuleInputsOutputs()
{
 	if(CHyperGraph* pGraph = m_view.GetGraph())
 	{
 		if(pGraph->IsFlowGraph())
 		{
		  CFlowGraph* pFlowGraph = static_cast<CFlowGraph*> (pGraph);
			
			if(pFlowGraph->GetIFlowGraph()->GetType() == IFlowGraph::eFGT_Module)
			{
					IFlowGraphModule* pModule = gEnv->pFlowSystem->GetIModuleManager()->GetModule(pGraph->GetName());

					if(pModule)
					{
							CFlowGraphEditModuleDlg dlg(pModule, this);
							dlg.DoModal();

							XmlNodeRef tempNode = gEnv->pSystem->CreateXmlNode("Graph");
							pGraph->Serialize(tempNode, false);
							pGraph->Serialize(tempNode, true);

							pGraph->SetModified(true);
					}
			}
 		}
 	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnFileNewUIAction()
{
	CString filename;
	if ( gEnv->pFlashUI && GetIEditor()->GetUIManager()->NewUIAction(filename) )
	{
		IUIAction* pUIAction = gEnv->pFlashUI->GetUIAction(PathUtil::GetFileName(filename.GetString()));
		if (pUIAction)
		{
			CFlowGraphManager* pManager = GetIEditor()->GetFlowGraphManager();
 			CFlowGraph* pFlowGraph = pManager->FindGraphForUIAction( pUIAction );
 			assert( pFlowGraph );
 			if ( pFlowGraph )
 				pManager->OpenView( pFlowGraph );
		}
		else
			SetGraph( NULL );
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnFileNewMatFXGraph()
{
	CString filename;
	CHyperGraph* pGraph = NULL;
	if (GetIEditor()->GetMatFxGraphManager()->NewMaterialFx(filename, &pGraph))
	{
		GetIEditor()->GetFlowGraphManager()->OpenView(pGraph);
	}
	else
	{
		SetGraph( NULL );
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnFileImport()
{
	CHyperGraph *pGraph = m_view.GetGraph();
	if (!pGraph)
	{
		Warning ("Please first create a FlowGraph to which to import");
		return;
	}

	CString filename;
	// if (CFileUtil::SelectSingleFile( EFILE_TYPE_ANY,filename,GRAPH_FILE_FILTER )) // game dialog
	if (CFileUtil::SelectFile (GRAPH_FILE_FILTER, "", filename )) // native dialog
	{
		CWaitCursor wait;
		bool ok = m_view.GetGraph()->Import( filename );
		if (!ok)
		{
			Warning ("Cannot import file '%s'.\nMake sure the file is actually a FlowGraph XML File.", filename.GetString());
		}
		m_view.InvalidateView(true);
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnFileExportSelection()
{
	CHyperGraph *pGraph = m_view.GetGraph();
	if (!pGraph)
		return;

	std::vector<CHyperNode*> nodes;
	if (!m_view.GetSelectedNodes( nodes ))
	{
		Warning( "You must have selected graph nodes to export" );
		return;
	}

	CString filename = CString(pGraph->GetName()) + ".xml";
	CString dir = Path::GetPath(filename);
	if (CFileUtil::SelectSaveFile( GRAPH_FILE_FILTER,"xml",dir,filename ))
	{
		CWaitCursor wait;
		CHyperGraphSerializer serializer( pGraph, 0 );

		for (int i = 0; i < nodes.size(); i++)
		{
			CHyperNode *pNode = nodes[i];
			serializer.SaveNode( pNode,true );
		}
		if (nodes.size() > 0)
		{
			XmlNodeRef node = XmlHelpers::CreateXmlNode("Graph");
			serializer.Serialize( node,false );
			bool ok =	XmlHelpers::SaveXmlNode( node,filename );
			if (!ok)
			{
				Warning("FlowGraph not saved to file '%s'", filename.GetString());
			}
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnFind()
{
	CXTPDockingPane* pSearchPane = GetDockingPaneManager()->FindPane(IDW_HYPERGRAPH_SEARCH_PANE);
	assert (pSearchPane != 0);

	// show the pane
	GetDockingPaneManager()->ShowPane(pSearchPane);

	// goto combo box
	CWnd* pWnd = m_pSearchOptionsView->GetDlgItem(IDC_COMBO_FIND);
	assert (pWnd != 0);
	m_pSearchOptionsView->GotoDlgCtrl(pWnd);
}

//////////////////////////////////////////////////////////////////////////
BOOL CHyperGraphDialog::OnComponentsViewToggle( UINT nID )
{
	switch (nID)
	{
	case ID_COMPONENTS_APPROVED:
		m_componentsViewMask ^= EFLN_APPROVED;
		break;
	case ID_COMPONENTS_ADVANCED:
		m_componentsViewMask ^= EFLN_ADVANCED;
		break;
	case ID_COMPONENTS_DEBUG:
		m_componentsViewMask ^= EFLN_DEBUG;
		break;
	//case ID_COMPONENTS_LEGACY:
	//	m_componentsViewMask ^= EFLN_LEGACY;
	//	break;
	//case ID_COMPONENTS_WIP:
	//	m_componentsViewMask ^= EFLN_WIP;
	//	break;
	//case ID_COMPONENTS_NOCATEGORY:
	//	m_componentsViewMask ^= EFLN_NOCATEGORY;
	//	break;
	case ID_COMPONENTS_OBSOLETE:
		m_componentsViewMask ^= EFLN_OBSOLETE;
		break;
	default:
		return FALSE;
	}
	UpdateComponentPaneTitle();
	m_componentsReportCtrl.SetComponentFilterMask(m_componentsViewMask);
	m_componentsReportCtrl.Reload();
	m_view.SetComponentViewMask(m_componentsViewMask);
	return TRUE;
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnComponentsViewUpdate( CCmdUI *pCmdUI )
{
	uint32 flag;

	switch (pCmdUI->m_nID)
	{
	case ID_COMPONENTS_APPROVED:
		flag = EFLN_APPROVED;
		break;
	case ID_COMPONENTS_ADVANCED:
		flag = EFLN_ADVANCED;
		break;
	case ID_COMPONENTS_DEBUG:
		flag = EFLN_DEBUG;
		break;
	//case ID_COMPONENTS_LEGACY:
	//	flag = EFLN_LEGACY;
	//	break;
	//case ID_COMPONENTS_WIP:
	//	flag = EFLN_WIP;
	//	break;
	//case ID_COMPONENTS_NOCATEGORY:
	//	flag = EFLN_NOCATEGORY;
	//	break;
	case ID_COMPONENTS_OBSOLETE:
		flag = EFLN_OBSOLETE;
		break;
	default:
		return;
	}
	pCmdUI->SetCheck( (m_componentsViewMask & flag) ? 1 : 0);
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::UpdateComponentPaneTitle()
{
	CString title = _T("Components");
	GetDockingPaneManager()->FindPane(IDW_HYPERGRAPH_COMPONENTS_PANE)->SetTitle(title);
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::ClearGraph()
{
	/*
	CHyperGraph *pGraph = m_view.GetGraph();
	if (pGraph && pGraph->IsModified())
	{
		if (AfxMessageBox( _T("Graph was modified, Save changes?"),MB_YESNO|MB_ICONQUESTION ) == IDYES)
		{
			OnFileSave();
		}
	}
	*/
}

void CHyperGraphDialog::OnComponentBeginDrag(CXTPReportRow* pRow, CPoint pt)
{
	if (!pRow)
		return;
	CComponentRecord* pRec = static_cast<CComponentRecord*> (pRow->GetRecord());
	if (!pRec)
		return;
	if (pRec->IsGroup())
		return;

	m_pDragImage = m_componentsReportCtrl.CreateDragImage(pRow);
	if (m_pDragImage)
	{
		m_pDragImage->BeginDrag(0, CPoint(-10, -10));

		m_dragNodeClass = pRec->GetName();

		ScreenToClient(&pt);

		CRect rc;
		GetWindowRect( rc );

		CPoint p = pt;
		ClientToScreen( &p );
		p.x -= rc.left;
		p.y -= rc.top;

		m_componentsReportCtrl.RedrawControl();
		m_pDragImage->DragEnter( this,p );
		SetCapture();
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnMouseMove(UINT nFlags, CPoint point) 
{
	if (m_pDragImage)
	{
		CRect rc;
		GetWindowRect( rc );
		CPoint p = point;
		ClientToScreen( &p );
		p.x -= rc.left;
		p.y -= rc.top;
		m_pDragImage->DragMove( p );
		return;
	}

	__super::OnMouseMove(nFlags, point);
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnLButtonUp(UINT nFlags, CPoint point) 
{
	if (m_pDragImage)
	{
		CPoint p;
		GetCursorPos( &p );

		::ReleaseCapture();
		m_pDragImage->DragLeave( this );
		m_pDragImage->EndDrag();
		m_pDragImage->DeleteImageList();
		// delete m_pDragImage; // FIXME: crashes 
		m_pDragImage = 0;

		CWnd *wnd = CWnd::WindowFromPoint( p );
		if (wnd == &m_view)
		{
			m_view.ScreenToClient(&p);
			m_view.CreateNode( m_dragNodeClass,p );
		}

		return;
	}
	__super::OnLButtonUp(nFlags, point);
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnPlay()
{
	GetIEditor()->GetFlowGraphDebuggerEditor()->ResumeGame();
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnStop()
{
	GetIEditor()->GetGameEngine()->EnableFlowSystemUpdate(false);
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnToggleDebug()
{
	ICVar *pToggle = gEnv->pConsole->GetCVar("fg_iEnableFlowgraphNodeDebugging");
	if(pToggle)
	{
		pToggle->Set((pToggle->GetIVal()>0)?0:1);
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnEraseDebug()
{
	std::list<CHyperGraph*>::iterator iter = m_graphList.begin();
	for (;iter != m_graphList.end();++iter)
	{
		CHyperGraph *pGraph = *iter;
		if(pGraph && pGraph->IsNodeActivationModified())
		{
			pGraph->ClearDebugPortActivation();

			IHyperGraphEnumerator *pEnum = pGraph->GetNodesEnumerator();
			for (IHyperNode *pINode = pEnum->GetFirst(); pINode; pINode = pEnum->GetNext())
			{
				CHyperNode *pNode = (CHyperNode*)pINode;
				pNode->Invalidate(true);
			}
			pEnum->Release();
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnPause()
{
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnStep()
{
	ICVar *pToggle = gEnv->pConsole->GetCVar("fg_iEnableFlowgraphNodeDebugging");
	if(pToggle && pToggle->GetIVal() == 2)
	{
		ICVar *pNextStep = gEnv->pConsole->GetCVar("fg_iDebugNextStep");
		if(pNextStep)
			pNextStep->Set(1);
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnUpdatePlay( CCmdUI *pCmdUI )
{
	if (GetIEditor()->GetGameEngine()->IsFlowSystemUpdateEnabled())
		pCmdUI->SetCheck(1);
	else
		pCmdUI->SetCheck(0);
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnUpdateStep( CCmdUI *pCmdUI )
{
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnUpdateDebug( CCmdUI *pCmdUI )
{
	ICVar *pToggle = gEnv->pConsole->GetCVar("fg_iEnableFlowgraphNodeDebugging");
	if(pToggle && pToggle->GetIVal() > 0)
		pCmdUI->SetCheck(1);
	else
		pCmdUI->SetCheck(0);
}

#define ID_GRAPHS_CHANGE_FOLDER 1
#define ID_GRAPHS_SELECT_ENTITY 2
#define ID_GRAPHS_REMOVE_GRAPH  3
#define ID_GRAPHS_ENABLE        4
#define ID_GRAPHS_ENABLE_ALL    5
#define ID_GRAPHS_DISABLE_ALL   6
#define ID_GRAPHS_RENAME_FOLDER 7
#define ID_GRAPHS_RENAME_GRAPH  8
#define ID_GRAPHS_REMOVE_NONENTITY_GRAPH  9
#define ID_BREAKPOINT_REMOVE_GRAPH 10
#define ID_BREAKPOINT_REMOVE_NODE 11
#define ID_BREAKPOINT_REMOVE_PORT 12
#define ID_BREAKPOINT_ENABLE 13
#define ID_TRACEPOINT_ENABLE 14
#define ID_GRAPHS_NEW_GLOBAL_MODULE 15
#define ID_GRAPHS_NEW_LEVEL_MODULE 16


void CHyperGraphDialog::GraphUpdateEnable(CFlowGraph* pFlowGraph, HTREEITEM hItem)
{
	// m_graphsTreeCtrl.Reload();  
	// this is way too slow and deletes the current open view incl. opened folders
	// that's why we use the stuff below. the tree ctrl from above needs
	// a major revamp.
	CEntityObject *pOwnerEntity = pFlowGraph->GetEntity();
	if (pOwnerEntity !=0) {
		int img = (pFlowGraph->IsEnabled() ? IMG_ENTITY : IMG_BIGX) + (pFlowGraph->HasError() ? IMG_ERROR_OFFSET : 0);
		m_graphsTreeCtrl.SetItemImage(hItem, img, img);
	} else if (pFlowGraph->GetAIAction() == 0) {
		int img = (pFlowGraph->IsEnabled() ? IMG_DEFAULT : IMG_SMALLX) + (pFlowGraph->HasError() ? IMG_ERROR_OFFSET : 0);
		m_graphsTreeCtrl.SetItemImage(hItem, img, img);
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnGraphsRightClick(NMHDR* pNMHDR, LRESULT* pResult)
{
	*pResult = TRUE;

	TDTreeItems chTreeItems;

	CPoint			screenPoint;
	GetCursorPos(&screenPoint);

	m_graphsTreeCtrl.GetSelectedItems(chTreeItems);

	// If no item is selected, we will try to select the item under the cursos.
	if (chTreeItems.empty())
	{
		UINT uFlags;
		CPoint point(screenPoint);
		ScreenToClient(&point);
		HTREEITEM hCurrentItem = m_graphsTreeCtrl.HitTest( point,&uFlags );
		if (TVHT_ONITEM & uFlags)
		{
			m_graphsTreeCtrl.Select( hCurrentItem,TVGN_CARET );
			chTreeItems.push_back(hCurrentItem);
		}
		else
		{
			// If no item was under the cursos, there is nothing to be done here.
			return;
		}		
	}

	CMenu menu;

	if (CreateContextMenu(menu,chTreeItems))
	{
		int		nCmd = menu.TrackPopupMenu( TPM_RETURNCMD|TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_NONOTIFY,screenPoint.x,screenPoint.y,this );
		ProcessMenu(nCmd,chTreeItems);
	}
}

void CHyperGraphDialog::OnBreakpointsRightClick(NMHDR* pNMHDR, LRESULT* pResult)
{
		*pResult = 0;

		CPoint screenPoint;
		if(GetCursorPos(&screenPoint))
		{
				UINT uFlags;
				CPoint point(screenPoint);
				m_breakpointsTreeCtrl.ScreenToClient(&point);
				const HTREEITEM hCurrentItem = m_breakpointsTreeCtrl.HitTest( point,&uFlags );
				if (hCurrentItem && (TVHT_ONITEM & uFlags))
				{						
						CMenu menu;
						if (CreateBreakpointContextMenu(menu,hCurrentItem))
						{
								const int	nCmd = menu.TrackPopupMenu( TPM_RETURNCMD|TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_NONOTIFY,screenPoint.x,screenPoint.y,this );
								ProcessBreakpointMenu(nCmd,hCurrentItem);
						}
				}	
		}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::EnableItems(HTREEITEM hItem, bool bEnable, bool bRecurse)
{
	HTREEITEM hChildItem = m_graphsTreeCtrl.GetChildItem(hItem);
	while (hChildItem != NULL)
	{
		if (m_graphsTreeCtrl.ItemHasChildren(hChildItem))
			EnableItems(hChildItem, bEnable, bRecurse);

		CHyperGraph* pGraph = (CHyperGraph*)m_graphsTreeCtrl.GetItemData(hChildItem);
		if (pGraph)
		{
			CFlowGraph* pFlowGraph = pGraph->IsFlowGraph() ? static_cast<CFlowGraph*> (pGraph) : 0;
			assert (pFlowGraph);
			if (pFlowGraph)
			{
				pFlowGraph->SetEnabled(bEnable);
				UpdateGraphProperties(pFlowGraph);
				// GraphUpdateEnable(pFlowGraph, hChildItem);
			}
		}
		hChildItem = m_graphsTreeCtrl.GetNextItem(hChildItem, TVGN_NEXT);
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::RenameItems(HTREEITEM hItem, CString& newGroupName, bool bRecurse)
{
	HTREEITEM hChildItem = m_graphsTreeCtrl.GetChildItem(hItem);
	while (hChildItem != NULL)
	{
		if (m_graphsTreeCtrl.ItemHasChildren(hChildItem))
			RenameItems(hChildItem, newGroupName, bRecurse);

		CHyperGraph* pGraph = (CHyperGraph*)m_graphsTreeCtrl.GetItemData(hChildItem);
		if (pGraph)
		{
			CFlowGraph* pFlowGraph = pGraph->IsFlowGraph() ? static_cast<CFlowGraph*> (pGraph) : 0;
			assert (pFlowGraph);
			if (pFlowGraph)
			{
				pFlowGraph->SetGroupName(newGroupName);
				UpdateGraphProperties(pFlowGraph);
				// GraphUpdateEnable(pFlowGraph, hChildItem);
			}
		}
		hChildItem = m_graphsTreeCtrl.GetNextItem(hChildItem, TVGN_NEXT);
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnGraphsDblClick(NMHDR* pNMHDR, LRESULT* pResult)
{
	*pResult = TRUE;

	CPoint point;
	GetCursorPos(&point);
	m_graphsTreeCtrl.ScreenToClient(&point);

	CEntityObject *pOwnerEntity = 0;
	CHyperGraph *pGraph = 0;

	UINT uFlags;
	HTREEITEM hItem = m_graphsTreeCtrl.HitTest( point,&uFlags );
	if ((hItem != NULL) && (TVHT_ONITEM & uFlags))
	{
		pGraph = (CHyperGraph*)m_graphsTreeCtrl.GetItemData(hItem);
		if (pGraph)
		{
			pOwnerEntity = ((CFlowGraph*)pGraph)->GetEntity();
		}
		if (pOwnerEntity)
		{
			CUndo undo( "Select Object(s)" );
			GetIEditor()->ClearSelection();
			GetIEditor()->SelectObject( pOwnerEntity );
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnGraphsSelChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
	*pResult = TRUE;
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	CHyperGraph *pGraph = (CHyperGraph*)pNMTreeView->itemNew.lParam;
	if (pGraph)
	{
		SetGraph( pGraph );
	}
}

//////////////////////////////////////////////////////////////////////////
BOOL CHyperGraphDialog::OnToggleBar( UINT nID )
{
	switch (nID)
	{
	case ID_VIEW_COMPONENTS:
		nID = IDW_HYPERGRAPH_COMPONENTS_PANE;
		break;
	case ID_VIEW_NODEINPUTS:
		nID = IDW_HYPERGRAPH_RIGHT_PANE;
		break;
	case ID_VIEW_GRAPHS:
		nID = IDW_HYPERGRAPH_TREE_PANE;
		break;
	case ID_VIEW_SEARCH:
		nID = IDW_HYPERGRAPH_SEARCH_PANE;
		break;
	case ID_VIEW_SEARCHRESULTS:
		nID = IDW_HYPERGRAPH_SEARCHRESULTS_PANE;
		break;
	case ID_VIEW_BREAKPOINTS:
		nID = IDW_HYPERGRAPH_BREAKPOINTS_PANE;
		break;
	default:
		return FALSE;
	}
	CXTPDockingPane *pBar = GetDockingPaneManager()->FindPane(nID);
	if (pBar)
	{
		if (pBar->IsClosed())
			GetDockingPaneManager()->ShowPane(pBar);
		else
			GetDockingPaneManager()->ClosePane(pBar);
		return TRUE;
	}
	return FALSE;
}

//////////////////////////////////////////////////////////////////////////
BOOL CHyperGraphDialog::OnMultiPlayerViewToggle( UINT nID )
{
	if (m_pGraphProperties)
		m_pGraphProperties->ShowMultiPlayer(!m_pGraphProperties->IsShowMultiPlayer());
	return TRUE;
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnMultiPlayerViewUpdate(CCmdUI* pCmdUI)
{
	if (m_pGraphProperties)
		pCmdUI->SetCheck(m_pGraphProperties->IsShowMultiPlayer() ? 1 : 0);
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnUpdateControlBar(CCmdUI* pCmdUI)
{
	UINT nID = 0;
	switch (pCmdUI->m_nID)
	{
	case ID_VIEW_COMPONENTS:
		nID = IDW_HYPERGRAPH_COMPONENTS_PANE;
		break;
	case ID_VIEW_NODEINPUTS:
		nID = IDW_HYPERGRAPH_RIGHT_PANE;
		break;
	case ID_VIEW_GRAPHS:
		nID = IDW_HYPERGRAPH_TREE_PANE;
		break;
	case ID_VIEW_SEARCH:
		nID = IDW_HYPERGRAPH_SEARCH_PANE;
		break;
	case ID_VIEW_SEARCHRESULTS:
		nID = IDW_HYPERGRAPH_SEARCHRESULTS_PANE;
		break;
	case ID_VIEW_BREAKPOINTS:
		nID = IDW_HYPERGRAPH_BREAKPOINTS_PANE;
		break;
	default:
		return;
	}
	CXTPCommandBars* pCommandBars = GetCommandBars();
	if(pCommandBars != NULL)
	{
		CXTPToolBar *pBar = pCommandBars->GetToolBar(nID);
		if (pBar)
		{
			pCmdUI->SetCheck( (pBar->IsVisible()) ? 1 : 0 );
			return;
		}
	}
	CXTPDockingPane *pBar = GetDockingPaneManager()->FindPane(nID);
	if (pBar)
	{
		pCmdUI->SetCheck( (!pBar->IsClosed()) ? 1 : 0 );
		return;
	}
	pCmdUI->SetCheck(0);
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::ShowResultsPane(bool bShow, bool bFocus)
{
	if (bShow) {
		CXTPDockingPane *pPane = GetDockingPaneManager()->FindPane(IDW_HYPERGRAPH_SEARCHRESULTS_PANE);
		assert (pPane != 0);
		GetDockingPaneManager()->ShowPane(pPane);
		if (bFocus)
			pPane->SetFocus();
	}
	else
		GetDockingPaneManager()->HidePane(IDW_HYPERGRAPH_SEARCHRESULTS_PANE);
}

//////////////////////////////////////////////////////////////////////////
// Called by the editor to notify the listener about the specified event.
void CHyperGraphDialog::OnEditorNotifyEvent( EEditorNotifyEvent event )
{
	switch ( event )
	{
	case eNotify_OnBeginSceneOpen:          // Sent when document is about to be opened.
		m_graphsTreeCtrl.SetIgnoreReloads(true);
		break;

	case eNotify_OnEndSceneOpen:            // Sent after document have been opened.
		m_graphsTreeCtrl.SetIgnoreReloads(false);
		m_graphsTreeCtrl.Reload();
		break;
	case eNotify_OnOpenGroup:
	case eNotify_OnCloseGroup:
		{
			m_graphsTreeCtrl.Reload();
		}
		break;
	case eNotify_OnEnableFlowSystemUpdate:
	case eNotify_OnDisableFlowSystemUpdate:
		{
			m_view.UpdateFrozen();
		}
		break;
	}
}

void CHyperGraphDialog::UpdateGraphProperties(CHyperGraph* pGraph)
{
	// TODO: real listener concept
	m_pGraphProperties->UpdateGraphProperties(pGraph);
	m_pGraphTokens->UpdateGraphProperties(pGraph);
	// TODO: real item update, not just this enable stuff
	if (pGraph->IsFlowGraph())
	{
		CFlowGraph* pFG = static_cast<CFlowGraph*> (pGraph);
		HTREEITEM hItem = m_graphsTreeCtrl.GetTreeItem(pFG);
		if (hItem)
		{
			GraphUpdateEnable(pFG, hItem);
		}
	}
}

void CHyperGraphDialog::UpdateTitle(CHyperGraph* pGraph)
{
	CString titleFormatter;
	if (pGraph)
	{
		titleFormatter += pGraph->GetFilename();
	}
	else
	{
		;
	}
	m_statusBar.SetPaneText(0, titleFormatter );
}

//////////////////////////////////////////////////////////////////////////
int CHyperGraphDialog::OnCreateCommandBar(LPCREATEBARSTRUCT lpCreatePopup)
{
	return FALSE;
}

//////////////////////////////////////////////////////////////////////////
int CHyperGraphDialog::OnCreateControl(LPCREATECONTROLSTRUCT lpCreateControl)
{
	CXTPToolBar* pToolBar = lpCreateControl->bToolBar? DYNAMIC_DOWNCAST(CXTPToolBar, lpCreateControl->pCommandBar): NULL;

	if ((lpCreateControl->nID == ID_FG_BACK || lpCreateControl->nID == ID_FG_FORWARD) && pToolBar)
	{
		CXTPControlPopup* pButtonNav = CXTPControlPopup::CreateControlPopup(xtpControlSplitButtonPopup);

		CXTPPopupToolBar* pNavBar = CXTPPopupToolBar::CreatePopupToolBar(GetCommandBars());
		pNavBar->EnableCustomization(FALSE);
		pNavBar->SetBorders(CRect(2, 2, 2, 2));
		pNavBar->DisableShadow();

		CXTPControlListBox* pControlListBox = (CXTPControlListBox*)pNavBar->GetControls()->Add(new CXTPControlListBox(), lpCreateControl->nID);
		pControlListBox->SetWidth(10);
		//pControlListBox->SetLinesMinMax(1, 6);
		pControlListBox->SetMultiplSel(FALSE);

		// CXTPControlStatic* pControlListBoxInfo = (CXTPControlStatic*)pUndoBar->GetControls()->Add(new CXTPControlStatic(), lpCreateControl->nID);
		// pControlListBoxInfo->SetWidth(140);


		pButtonNav->SetCommandBar(pNavBar);
		pNavBar->InternalRelease();

		lpCreateControl->pControl = pButtonNav;
		return TRUE;
	}

	return FALSE;
}

CXTPControlStatic* FindInfoControl(CXTPControl* pControl)
{
	CXTPCommandBar* pCommandBar = pControl->GetParent();

	for (int i = 0; i < pCommandBar->GetControls()->GetCount(); i++)
	{
		CXTPControlStatic* pControlStatic = DYNAMIC_DOWNCAST(CXTPControlStatic, pCommandBar->GetControl(i));
		if (pControlStatic && pControlStatic->GetID() == pControl->GetID())
		{
			return pControlStatic;
		}

	}
	return NULL;
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnNavListBoxControlSelChange(NMHDR* pNMHDR, LRESULT* pRes)
{
	ASSERT(pNMHDR != NULL);
	ASSERT(pRes != NULL);

	CXTPControlListBox* pControlListBox = DYNAMIC_DOWNCAST(CXTPControlListBox, ((NMXTPCONTROL*)pNMHDR)->pControl);
	if (pControlListBox)
	{
		CListBox* pListBox = pControlListBox->GetListCtrl();
		int index = pListBox->GetCurSel();
		m_pNavGraph = index == LB_ERR ? 0 : reinterpret_cast<CHyperGraph*> (pListBox->GetItemDataPtr(index));

		/*
		CXTPControlStatic* pInfo = FindInfoControl(pControlListBox);
		if (pInfo)
		{
			CString str;
			str.Format(_T("Undo %i Actions"), pControlListBox->GetListCtrl()->GetSelCount());
			pInfo->SetCaption(str);
			pInfo->DelayRedrawParent();
		}
		*/

		*pRes = 1;
	}
}

int CalcWidth(CListBox* pListBox)
{
	int nMaxTextWidth = 0;
	int nScrollWidth = 0;














	CDC *pDC = pListBox->GetDC();
	if (pDC)
	{
		CFont *pOldFont = pDC->SelectObject(pListBox->GetFont());
		CString Text;
		const int nItems = pListBox->GetCount();
		for (int i = 0; i < nItems; ++i)
		{
			pListBox->GetText(i, Text);
			const int nTextWidth = pDC->GetTextExtent(Text).cx;
			if (nTextWidth > nMaxTextWidth)
				nMaxTextWidth = nTextWidth;
		}
		pDC->SelectObject(pOldFont);
		VERIFY(pListBox->ReleaseDC(pDC) != 0);
	}
	else
	{
		ASSERT(FALSE);
	}
	return nMaxTextWidth+nScrollWidth;
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnNavListBoxControlPopup(NMHDR* pNMHDR, LRESULT* pRes)
{
	ASSERT(pNMHDR != NULL);
	ASSERT(pRes != NULL);
	CXTPControlListBox* pControlListBox = DYNAMIC_DOWNCAST(CXTPControlListBox, ((NMXTPCONTROL*)pNMHDR)->pControl);
	if (pControlListBox)
	{
		m_pNavGraph = 0;
		CListBox* pListBox = pControlListBox->GetListCtrl();
		pListBox->ResetContent();

		bool forward = pControlListBox->GetID() == ID_FG_FORWARD;
		CString name;
		CString groupName;

		if (forward)
		{
			std::list<CHyperGraph*>::iterator iterStart;
			std::list<CHyperGraph*>::iterator iterEnd;
			iterStart = m_graphIterCur;
			if (iterStart != m_graphList.end())
				++iterStart;
			iterEnd = m_graphList.end();
			while (iterStart != iterEnd)
			{
				GetPrettyName(*iterStart, name, groupName);
				groupName+=":";
				groupName+=name;
				int index = pListBox->AddString(groupName);
				pListBox->SetItemDataPtr(index, (*iterStart));
				++iterStart;
			}
		}
		else
		{
			std::list<CHyperGraph*>::iterator iterStart;
			std::list<CHyperGraph*>::iterator iterEnd;
			iterStart = m_graphIterCur;
			if (iterStart != m_graphList.begin())
			{
				iterEnd = m_graphList.begin();
				do 
				{
					--iterStart;
					GetPrettyName(*iterStart, name, groupName);
					groupName+=":";
					groupName+=name;
					int index = pListBox->AddString(groupName);
					pListBox->SetItemDataPtr(index, (*iterStart));
				}
				while (iterStart != iterEnd);
			}
		}

		int width = CalcWidth(pListBox)+4;
		pListBox->SetHorizontalExtent(width);
		pControlListBox->SetWidth(width);

		CXTPControlStatic* pInfo = FindInfoControl(pControlListBox);
		if (pInfo)
		{
			CString str;
			pInfo->SetCaption(_T("Undo 0 Actions"));
			pInfo->DelayRedrawParent();
		}

		*pRes = 1;
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnUpdateNav(CCmdUI* pCmdUI)
{
	BOOL enable = FALSE;

	switch (pCmdUI->m_nID)
	{
	case ID_FG_BACK:
		enable = m_graphList.size() > 0 && m_graphIterCur != m_graphList.begin();
		break;
	case ID_FG_FORWARD:
		enable = m_graphList.size() > 0 && m_graphIterCur != --m_graphList.end() && m_graphIterCur != m_graphList.end();
		break;
	default:
		// don't do anything
		return;
	}
	pCmdUI->Enable(enable);
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnNavForward()
{
	if (m_pNavGraph != 0)
	{
		SetGraph(m_pNavGraph);
		m_pNavGraph = 0;
	}
	else if (m_graphList.size() > 0 && m_graphIterCur != -- m_graphList.end() && m_graphIterCur != m_graphList.end())
	{
		std::list<CHyperGraph*>::iterator iter = m_graphIterCur;
		++iter;
		CHyperGraph* pGraph = *(iter);
		SetGraph(pGraph);
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnNavBack()
{
	if (m_pNavGraph != 0)
	{
		SetGraph(m_pNavGraph);
		m_pNavGraph = 0;
	}
	else if (m_graphList.size() > 0 && m_graphIterCur != m_graphList.begin())
	{
		std::list<CHyperGraph*>::iterator iter = m_graphIterCur;
		--iter;
		CHyperGraph* pGraph = *(iter);
		SetGraph(pGraph);
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnComponentSearchEditChange()
{
	CString keyword;
	m_componentSearchEdit.GetWindowText(keyword);
	m_componentsReportCtrl.SetSearchKeyword(keyword);
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::UpdateNavHistory()
{
	// early return, when history is empty anyway [loading...]
	if (m_graphList.empty())
		return;

	CFlowGraphManager* pMgr = GetIEditor()->GetFlowGraphManager();
	const int fgCount = pMgr->GetFlowGraphCount();
	std::set<CHyperGraph*> graphs;
	for (int i=0; i<fgCount; ++i)
	{
		graphs.insert(pMgr->GetFlowGraph(i));
	}

	// validate history
	bool adjustCur = false;
	std::list<CHyperGraph*>::iterator iter = m_graphList.begin();
	while (iter != m_graphList.end())
	{
		CHyperGraph* pGraph = *iter;
		if (graphs.find(pGraph) == graphs.end())
		{
			// remove graph from history
			std::list<CHyperGraph*>::iterator toDelete = iter;
			++iter;
			if (m_graphIterCur == toDelete)
				adjustCur = true;

			m_graphList.erase(toDelete);
		}
		else
		{
			++iter;
		}
	}

	// adjust current iterator in case the current graph got deleted
	if (adjustCur)
	{
		m_graphIterCur = m_graphList.end();
	}
}


//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnHyperGraphManagerEvent( EHyperGraphEvent event, IHyperGraph* pGraph, IHyperNode* pNode )
{
	switch (event)
	{
		case EHG_GRAPH_REMOVED:
			UpdateNavHistory();
			break;
		case EHG_GRAPH_UPDATE_FROZEN:
			m_view.UpdateFrozen();
			break;
		case EHG_GRAPH_CLEAR_SELECTION:
			m_view.ClearSelection();
			m_view.InvalidateView(true);
			break;
		case EHG_GRAPH_INVALIDATE:
			m_view.InvalidateView(true);
			break;
	}
}

//////////////////////////////////////////////////////////////////////////
bool CHyperGraphDialog::CreateContextMenu( CMenu& roMenu,TDTreeItems& rchSelectedItems )
{
	enum EMenuFlags
	{
		eGraphValid									=0,
		eGraphEnabled								=1,
		eIsOwnedByEntity						=2,
		eIsAssociatedToFlowGraph		=3,
		eIsEntitySubFolder					=4,
		eIsEntitySubFolderOrFolder  =5,
		eIsModule = 6,
		eIsModuleFolder = 7,

		eTotalEMenuFlags						= 8,
	};

	bool aboMenuFlags[eTotalEMenuFlags];

	memset(aboMenuFlags,1,sizeof(bool)*eTotalEMenuFlags);

	bool boIsEnabled(false);
	int nTotalTreeItems(0);
	int nCurrentTreeItem(0);

	nTotalTreeItems=rchSelectedItems.size();
	for (nCurrentTreeItem=0;nCurrentTreeItem<nTotalTreeItems;++nCurrentTreeItem)
	{		
		HTREEITEM& rhCurrentTreeItem=rchSelectedItems[nCurrentTreeItem];
		if (!IsGraphEnabled(rhCurrentTreeItem,boIsEnabled))
		{
			aboMenuFlags[eGraphValid]=false;
		}
		else if (nCurrentTreeItem==0)
		{
			aboMenuFlags[eGraphEnabled]=boIsEnabled;
		}
		else
		{
			if (aboMenuFlags[eGraphEnabled]!=boIsEnabled)
			{
				aboMenuFlags[eGraphValid]=false;
			}
		}

		if (!IsOwnedByAnEntity(rhCurrentTreeItem))
		{
			aboMenuFlags[eIsOwnedByEntity]=false;
		}

		if(!IsGraphType(rhCurrentTreeItem, IFlowGraph::eFGT_Module))
		{
			aboMenuFlags[eIsModule]=false;
		}

		if (!IsAssociatedToFlowGraph(rhCurrentTreeItem))
		{
			aboMenuFlags[eIsAssociatedToFlowGraph]=false;
		}

		if (!IsAnEntitySubFolder(rhCurrentTreeItem))
		{
			aboMenuFlags[eIsEntitySubFolder]=false;
		}

		if (!IsAnEntityFolderOrSubFolder(rhCurrentTreeItem))
		{
			aboMenuFlags[eIsEntitySubFolderOrFolder]=false;
		}

		CString itemName = m_graphsTreeCtrl.GetItemText(rhCurrentTreeItem);
		if (itemName.Compare(g_FGModulesFolderName))
		{
				aboMenuFlags[eIsModuleFolder]=false;
		}
	}

	int nCurrentFlag(0);
	bool boMustAddSomeMenu(false);
	for (nCurrentFlag=0;nCurrentFlag<eTotalEMenuFlags;++nCurrentFlag)
	{
		if (aboMenuFlags[nCurrentFlag])
		{
			boMustAddSomeMenu=true;
			break;
		}
	}

	if (!boMustAddSomeMenu)
	{
		return false;
	}

	// As there will be at least one menu option, it's worth creating the menu.
	roMenu.CreatePopupMenu();

	if(aboMenuFlags[eIsModuleFolder])
	{
		roMenu.AppendMenu(MF_STRING, ID_GRAPHS_NEW_GLOBAL_MODULE, "New Global FG Module");
		roMenu.AppendMenu(MF_STRING, ID_GRAPHS_NEW_LEVEL_MODULE, "New Level FG Module");
	}

	if (aboMenuFlags[eGraphValid])
	{
		if(!aboMenuFlags[eIsModule])
			roMenu.AppendMenu( MF_STRING,ID_GRAPHS_ENABLE,aboMenuFlags[eGraphEnabled]?"Enable":"Disable");

		// we can only rename the custom graphs found in Files node
		if( !aboMenuFlags[eIsOwnedByEntity] )
		{
			if(!aboMenuFlags[eIsModule])
			{
				string renameMessage = "Rename Graph";
				roMenu.AppendMenu( MF_SEPARATOR );
				roMenu.AppendMenu( MF_STRING,ID_GRAPHS_RENAME_GRAPH, renameMessage);
			}
			
			string deleteMessage = "Delete Graph";

			if(aboMenuFlags[eIsModule])
			{
				deleteMessage = "Delete Module";
			}

			roMenu.AppendMenu( MF_STRING,ID_GRAPHS_REMOVE_NONENTITY_GRAPH, deleteMessage);

			if(!aboMenuFlags[eIsModule])
				roMenu.AppendMenu( MF_SEPARATOR );
		}
	}

	if (aboMenuFlags[eIsOwnedByEntity])
	{
		roMenu.AppendMenu( MF_STRING,ID_GRAPHS_SELECT_ENTITY,"Select Entity" );
		roMenu.AppendMenu( MF_SEPARATOR );
		roMenu.AppendMenu( MF_STRING,ID_GRAPHS_REMOVE_GRAPH,"Delete Graph" );
	}

	if (aboMenuFlags[eIsAssociatedToFlowGraph] && !aboMenuFlags[eIsModule])
	{
		roMenu.AppendMenu( MF_STRING,ID_GRAPHS_CHANGE_FOLDER,"Change Folder" );
	}

	if (aboMenuFlags[eIsEntitySubFolder])
	{
		// Renaming does not make sense in batch considering the current usage of the interface.
		if (rchSelectedItems.size()==1)
		{
			roMenu.AppendMenu(MF_STRING,ID_GRAPHS_RENAME_FOLDER,"RenameFolder/MoveGraphs");
		}		
	}

	if (aboMenuFlags[eIsEntitySubFolderOrFolder])
	{
			roMenu.AppendMenu(MF_STRING,ID_GRAPHS_ENABLE_ALL,"Enable All");
			roMenu.AppendMenu(MF_STRING,ID_GRAPHS_DISABLE_ALL,"Disable All");
	}

	return true;
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::ProcessMenu( int nMenuOption, TDTreeItems& rchSelectedItem )
{
	CString currentGroupName;

	CEntityObject *pOwnerEntity = 0;
	CHyperGraph *pGraph = 0;
	CFlowGraph *pFlowGraph = 0;

	std::vector<CEntityObject*>				cSelectedEntities;
	std::vector<CHyperGraph*>		cSelectedGraphs;

	int nTotalSelectedItems(0);
	int nCurrentSelectedItem(0);

	nTotalSelectedItems=rchSelectedItem.size();
	for (nCurrentSelectedItem=0;nCurrentSelectedItem<nTotalSelectedItems;++nCurrentSelectedItem)
	{
		HTREEITEM& rhCurrentSelectedItem=rchSelectedItem[nCurrentSelectedItem];

		pGraph = (CHyperGraph*)m_graphsTreeCtrl.GetItemData(rhCurrentSelectedItem);
		if (pGraph)
			pFlowGraph = pGraph->IsFlowGraph() ? static_cast<CFlowGraph*> (pGraph) : 0;

		if (pFlowGraph)
		{
			pOwnerEntity = pFlowGraph->GetEntity();
		}

		currentGroupName = m_graphsTreeCtrl.GetItemText(rhCurrentSelectedItem);

		switch (nMenuOption)
		{
		case ID_GRAPHS_ENABLE_ALL:
		case ID_GRAPHS_DISABLE_ALL:
			{
				bool enabled (nMenuOption == ID_GRAPHS_ENABLE_ALL);
				m_graphsTreeCtrl.SetRedraw(FALSE);
				EnableItems(rhCurrentSelectedItem, enabled, true);
				m_graphsTreeCtrl.SetRedraw(TRUE);
			}
			break;
		case ID_GRAPHS_RENAME_FOLDER:
			{
				bool bIsAction = false;
				CFlowGraphManager* pFlowGraphManager = GetIEditor()->GetFlowGraphManager();
				std::set<CString> groupsSet;
				pFlowGraphManager->GetAvailableGroups(groupsSet, bIsAction);

				CString groupName;
				bool bDoNew  = true;
				bool bChange = false;

				if (groupsSet.size() > 0)
				{
					std::vector<CString> groups (groupsSet.begin(), groupsSet.end());

					CGenericSelectItemDialog gtDlg(this);
					if (bIsAction == false)
						gtDlg.SetTitle(_T("Choose New Group for the Flow Graph"));
					else
						gtDlg.SetTitle(_T("Choose Group for the AIAction Graph"));

					gtDlg.PreSelectItem(currentGroupName);
					gtDlg.SetItems(groups);
					gtDlg.AllowNew(true);
					switch (gtDlg.DoModal())
					{
					case IDOK:
						groupName = gtDlg.GetSelectedItem();
						bChange = true;
						bDoNew  = false;
						break;
					case IDNEW:
						// bDoNew  = true; // is true anyway
						break;
					default:
						bDoNew = false;
						break;
					}
				}

				if (bDoNew)
				{
					CStringDlg dlg ( bIsAction == false ?
						_T("Enter Group Name for the Flow Graph") :
					_T("Enter Group Name for the AIAction Graph") );
					dlg.SetString(currentGroupName);
					if (dlg.DoModal() == IDOK)
					{
						bChange = true;
						groupName = dlg.GetString();
					}
				}

				if (bChange && groupName != currentGroupName)
				{
					m_graphsTreeCtrl.SetIgnoreReloads(true);
					m_graphsTreeCtrl.SetRedraw(FALSE);
					RenameItems(rhCurrentSelectedItem, groupName, true);
					m_graphsTreeCtrl.SetRedraw(TRUE);
					m_graphsTreeCtrl.SetIgnoreReloads(false);
					m_graphsTreeCtrl.Reload();
				}

			}
			break;

		case ID_GRAPHS_SELECT_ENTITY:
			{
				if (pOwnerEntity)
				{
					CUndo undo( "Select Object(s)" );
					if (nCurrentSelectedItem==0)
					{
						GetIEditor()->ClearSelection();
					}
					GetIEditor()->SelectObject( pOwnerEntity );
				}
				/*
				CStringDlg dlg( "Rename Graph" );
				dlg.SetString( pGraph->GetName() );
				if (dlg.DoModal() == IDOK)
				{
				pGraph->SetName( dlg.GetString() );
				m_graphsTreeCtrl.SetItemText( hItem,dlg.GetString() );
				}
				*/
			}
			break;
		case ID_GRAPHS_NEW_GLOBAL_MODULE:
			{
				OnFileNewGlobalFGModule();
			}
			break;
		case ID_GRAPHS_NEW_LEVEL_MODULE:
			{
				OnFileNewLevelFGModule();
			}
			break;
		case ID_GRAPHS_REMOVE_NONENTITY_GRAPH:
			{
				bool bIsModule = (pFlowGraph->GetIFlowGraph()->GetType() == IFlowGraph::eFGT_Module);

				CString message = "";

				if(bIsModule)
					message = "Delete Module: ";
				else
					message = "Delete Graph: ";

				message += pFlowGraph->GetName();
				message += "?";

				if (MessageBox( message,"Confirm",MB_OKCANCEL )==IDOK)
				{
					CUndo undo( "Delete Graph" );
					
					HTREEITEM hAdjacentItem = NULL;
					m_graphsTreeCtrl.DeleteNonEntityItem(pGraph, hAdjacentItem);

					CHyperGraph* pAdjacentGraph = NULL;
					if( hAdjacentItem )
						pAdjacentGraph = (CHyperGraph*)m_graphsTreeCtrl.GetItemData(hAdjacentItem);

					if( pAdjacentGraph )
					{
						SetGraph(pAdjacentGraph);
					}
					else
					{
						m_view.SetGraph(0);
						m_pGraphProperties->SetGraph(0);
						UpdateTitle(0);							
						m_graphIterCur = m_graphList.end();
						if( hAdjacentItem )
							m_graphsTreeCtrl.SelectItem(hAdjacentItem);
					}

					if(bIsModule)
					{
						IFlowGraphModuleManager* pModuleManager = gEnv->pFlowSystem->GetIModuleManager();

						if(pModuleManager)
						{
							pModuleManager->DeleteModuleXML(pFlowGraph->GetName());

							CEditorFlowGraphModuleManager* pMManager = GetIEditor()->GetFlowGraphModuleManager();

							if(pMManager)
							{
								pMManager->DeleteModuleFlowGraph(pFlowGraph);
							}
						}
					}

					stl::find_and_erase(m_graphList, pGraph);

					if(false == bIsModule)
						SAFE_RELEASE(pGraph);
				}
			}
			break;

		case ID_GRAPHS_REMOVE_GRAPH:
			{							
				if (pOwnerEntity)
				{
					cSelectedEntities.push_back(pOwnerEntity);				
				}

				// Hack to do the operation only when all data is gahtered...
				if (nCurrentSelectedItem==nTotalSelectedItems-1)
				{
					CString str="Delete Flow Graph for Entity(ies) :\n";

					int nTotalEntities=MIN(cSelectedEntities.size(),7);
					int nCurrentEntity(0);
					for (nCurrentEntity=0;nCurrentEntity<nTotalEntities;++nCurrentEntity)
					{
						str+=(const char*)cSelectedEntities[nCurrentEntity]->GetName();
						str+="\n";
					}

					if (nTotalEntities<cSelectedEntities.size())
					{
						str+="...";
					}

					if (MessageBox( str,"Confirm",MB_OKCANCEL )==IDOK)
					{
						CUndo undo( "Delete Entity Graph" );
						nTotalEntities=cSelectedEntities.size();
						
						HTREEITEM hAdjacentItem = NULL;
						for (nCurrentEntity=0;nCurrentEntity<nTotalEntities;++nCurrentEntity)
						{
							if( m_graphsTreeCtrl.DeleteEntityItem(cSelectedEntities[nCurrentEntity], hAdjacentItem) )
								cSelectedEntities[nCurrentEntity]->RemoveFlowGraph(false);
						}

						CHyperGraph* pGraph = NULL;
						if( hAdjacentItem )
							pGraph = (CHyperGraph*)m_graphsTreeCtrl.GetItemData(hAdjacentItem);

						if( pGraph )
						{
							SetGraph(pGraph);
						}
						else
						{
							m_view.SetGraph(0);
							m_pGraphProperties->SetGraph(0);
							m_pGraphTokens->SetGraph(0);
							UpdateTitle(0);							
							m_graphIterCur = m_graphList.end();
							if( hAdjacentItem )
								m_graphsTreeCtrl.SelectItem(hAdjacentItem);
						}
					}
				}
			}
			break;
		case ID_GRAPHS_ENABLE:
			{
				if (pFlowGraph)
				{
					// Toggle enabled of graph.
					pFlowGraph->SetEnabled( !pGraph->IsEnabled() );
					// GraphUpdateEnable(pFlowGraph, hItem);
					UpdateGraphProperties(pGraph);
					m_graphsTreeCtrl.SetRedraw(TRUE);
				}
			}
			break;
		case ID_GRAPHS_RENAME_GRAPH:
			{
				if (pFlowGraph)
				{
					bool bIsModule = (pFlowGraph->GetIFlowGraph()->GetType() == IFlowGraph::eFGT_Module);
					string renameMessage = "Edit Flow Graph name";

					if(bIsModule)
						renameMessage = "Edit Module name";

					// show the dialog to input new name
					CStringInputDialog dlg( pFlowGraph->GetName(), renameMessage.c_str() );

					// if all OK, rename it
					if( IDOK == dlg.DoModal() )
					{
						if( dlg.GetResultingText().IsEmpty() )
						{
							AfxMessageBox( _T( "You supplied an empty name, no change was made" ) );
							break;
						}
						

						if(bIsModule)
						{
							IFlowGraphModuleManager* pModuleManager = gEnv->pFlowSystem->GetIModuleManager();

							if(pModuleManager)
							{
								pModuleManager->RenameModuleXML(pFlowGraph->GetName(), dlg.GetResultingText().GetString());
							}
						}
						

						// rename flowgraph
						pFlowGraph->SetName( dlg.GetResultingText() );

											
						UpdateGraphProperties( pGraph );
						m_graphsTreeCtrl.SetRedraw( TRUE );
						m_graphsTreeCtrl.Reload();
						SetGraph( 0 );
					}
				}
			}
			break;
		case ID_GRAPHS_CHANGE_FOLDER:
			{
				if (pFlowGraph)
				{
					/*
					CStringDlg dlg( "Change Graph Folder" );
					dlg.SetString( pGraph->GetGroupName() );
					if (dlg.DoModal() == IDOK)
					{
					pGraph->SetGroupName( dlg.GetString() );
					m_graphsTreeCtrl.Reload();
					}
					*/
					if (pGraph)
					{
						cSelectedGraphs.push_back(pGraph);
					}					

					if (nCurrentSelectedItem==nTotalSelectedItems-1)
					{
						bool bIsAction = pFlowGraph->GetAIAction();
						CFlowGraphManager* pFlowGraphManager = (CFlowGraphManager*) pFlowGraph->GetManager();
						std::set<CString> groupsSet;
						pFlowGraphManager->GetAvailableGroups(groupsSet, bIsAction);

						CString groupName;
						bool bDoNew  = true;
						bool bChange = false;

						if (groupsSet.size() > 0)
						{
							std::vector<CString> groups (groupsSet.begin(), groupsSet.end());

							CGenericSelectItemDialog gtDlg(this);
							if (bIsAction == false)
								gtDlg.SetTitle(_T("Choose Group for the Flow Graph(s)"));
							else
								gtDlg.SetTitle(_T("Choose Group for the AIAction Graph(s)"));

							gtDlg.PreSelectItem(pFlowGraph->GetGroupName());
							gtDlg.SetItems(groups);
							gtDlg.AllowNew(true);
							switch (gtDlg.DoModal())
							{
							case IDOK:
								groupName = gtDlg.GetSelectedItem();
								bChange = true;
								bDoNew  = false;
								break;
							case IDNEW:
								// bDoNew  = true; // is true anyway
								break;
							default:
								bDoNew = false;
								break;
							}
						}

						if (bDoNew)
						{
							CStringDlg dlg ( bIsAction == false ?
								_T("Enter Group Name for the Flow Graph(s)") :
							_T("Enter Group Name for the AIAction Graph(s)") );
							dlg.SetString(pFlowGraph->GetGroupName());
							if (dlg.DoModal() == IDOK)
							{
								bChange = true;
								groupName = dlg.GetString();
							}
						}

					 int nTotalSelectedGraphs(0);
					 int nCurrentlySelectedGraph(0);

					 nTotalSelectedGraphs=cSelectedGraphs.size();
					 for (nCurrentlySelectedGraph=0;nCurrentlySelectedGraph<nTotalSelectedGraphs;++nCurrentlySelectedGraph)
					 {
						 CHyperGraph*&	rpoCurrentGraph=cSelectedGraphs[nCurrentlySelectedGraph];
						 if (bChange && groupName != rpoCurrentGraph->GetGroupName())
						 {
							 rpoCurrentGraph->SetGroupName( groupName );
							 m_graphsTreeCtrl.Reload();
						 }
					 }
					}
				}
			}
			break;
		case IDC_NEW:
			break;
		}
	}
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::DeleteItem(CEntityObject* pEntity)
{
	HTREEITEM hAdjacentItem = NULL;
	m_graphsTreeCtrl.DeleteEntityItem(pEntity, hAdjacentItem);
}


//////////////////////////////////////////////////////////////////////////
bool CHyperGraphDialog::IsAnEntityFolderOrSubFolder(HTREEITEM hSelectedItem)
{
	HTREEITEM	hParentItem(NULL);
	CString		strGroupName;

	if (IsAssociatedToFlowGraph(hSelectedItem))
	{
		return false;
	}

	hParentItem=m_graphsTreeCtrl.GetParentItem(hSelectedItem);
	strGroupName=m_graphsTreeCtrl.GetItemText(hSelectedItem);

	if (
			(strGroupName == g_EntitiesFolderName) 
			|| 
			(hParentItem != 0 && m_graphsTreeCtrl.GetItemText(hParentItem) == g_EntitiesFolderName)
		 )
	{
		return true;
	}

	return false;
}
//////////////////////////////////////////////////////////////////////////
bool CHyperGraphDialog::IsAnEntitySubFolder(HTREEITEM hSelectedItem)
{
	HTREEITEM	hParentItem(NULL);
	CString		strGroupName;

	if (IsAssociatedToFlowGraph(hSelectedItem))
	{
		return false;
	}

	hParentItem=m_graphsTreeCtrl.GetParentItem(hSelectedItem);
	strGroupName=m_graphsTreeCtrl.GetItemText(hParentItem);

	if (hParentItem != 0 && 
		(strGroupName != g_AIActionsFolderName) && // I think this would never happen togheter with the other condition...
		(strGroupName != g_FGModulesFolderName)
		)
	{
		return true;
	}

	return false;
}
//////////////////////////////////////////////////////////////////////////
bool CHyperGraphDialog::IsGraphEnabled(HTREEITEM hSelectedItem,bool &boIsEnabled)
{
	CHyperGraph *pGraph = 0;
	CFlowGraph *pFlowGraph = 0;

	pGraph = (CHyperGraph*)m_graphsTreeCtrl.GetItemData(hSelectedItem);
	if (pGraph)
	{
		pFlowGraph = pGraph->IsFlowGraph() ? static_cast<CFlowGraph*> (pGraph) : 0;
	}

	if (pFlowGraph)
	{
		if (pFlowGraph->GetAIAction() == 0 && pFlowGraph->GetUIAction() == 0)
		{
			if (!pGraph->IsEnabled())
			{
				boIsEnabled=true;
			}
			else
			{
				boIsEnabled=false;
			}
			return true;
		}
	}

	return false;
}

bool CHyperGraphDialog::IsGraphType(HTREEITEM hSelectedItem, IFlowGraph::EFlowGraphType type)
{
	CHyperGraph *pGraph = 0;
	CFlowGraph *pFlowGraph = 0;
	CEntityObject *pOwnerEntity = 0;

	pGraph = (CHyperGraph*)m_graphsTreeCtrl.GetItemData(hSelectedItem);
	if (pGraph)
	{
		pFlowGraph = pGraph->IsFlowGraph() ? static_cast<CFlowGraph*> (pGraph) : 0;
	}

	if (pFlowGraph)
	{
		return pFlowGraph->GetIFlowGraph()->GetType() == type;
	}
	return false;
}

//////////////////////////////////////////////////////////////////////////
bool CHyperGraphDialog::IsOwnedByAnEntity(HTREEITEM hSelectedItem)
{
	CHyperGraph *pGraph = 0;
	CFlowGraph *pFlowGraph = 0;
	CEntityObject *pOwnerEntity = 0;

	pGraph = (CHyperGraph*)m_graphsTreeCtrl.GetItemData(hSelectedItem);
	if (pGraph)
	{
		pFlowGraph = pGraph->IsFlowGraph() ? static_cast<CFlowGraph*> (pGraph) : 0;
	}

	if (pFlowGraph)
	{
		pOwnerEntity = pFlowGraph->GetEntity();
		if (pOwnerEntity)
		{
			return true;
		}
	}
	return false;
}
//////////////////////////////////////////////////////////////////////////
bool CHyperGraphDialog::IsAssociatedToFlowGraph(HTREEITEM hSelectedItem)
{
	CHyperGraph *pGraph = (CHyperGraph*)m_graphsTreeCtrl.GetItemData(hSelectedItem);

	if (pGraph)
	{
		return pGraph->IsFlowGraph();
	}

	return false;
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnCustomize()
{
	CMFCUtils::ShowShortcutsCustomizeDlg(GetCommandBars(), IDR_HYPERGRAPH, "FlowGraph");
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnExportShortcuts()
{
	CMFCUtils::ExportShortcuts(GetCommandBars()->GetShortcutManager());
}

//////////////////////////////////////////////////////////////////////////
void CHyperGraphDialog::OnImportShortcuts()
{
	CMFCUtils::ImportShortcuts(GetCommandBars()->GetShortcutManager(), "FlowGraph");
}

bool CHyperGraphDialog::CreateBreakpointContextMenu( CMenu& roMenu,HTREEITEM hItem )
{
	SBreakpointItem* breakpointItem = reinterpret_cast<SBreakpointItem*>(m_breakpointsTreeCtrl.GetItemData( hItem ));

	if(breakpointItem == NULL)
		return false;

	roMenu.CreatePopupMenu();

	switch (breakpointItem->type)
	{
	case SBreakpointItem::eIT_Graph:
		{
			roMenu.AppendMenu( MF_STRING,ID_BREAKPOINT_REMOVE_GRAPH,"Remove Breakpoints for Graph");
		}
		break;
	case SBreakpointItem::eIT_Node:
		{
			roMenu.AppendMenu( MF_STRING,ID_BREAKPOINT_REMOVE_NODE,"Remove Breakpoints for Node");
		}
		break;
	case SBreakpointItem::eIT_Port:
		{
			if (m_pFlowGraphDebugger)
			{
				roMenu.AppendMenu( MF_STRING,ID_BREAKPOINT_REMOVE_PORT,"Remove Breakpoint");
				roMenu.AppendMenu( MF_SEPARATOR );

				const bool bIsEnabled = m_pFlowGraphDebugger->IsBreakpointEnabled(breakpointItem->flowgraph, breakpointItem->addr);
				roMenu.AppendMenu( MF_STRING | (bIsEnabled ? MF_CHECKED : MF_UNCHECKED),ID_BREAKPOINT_ENABLE,"Enabled");
				const bool bIsTracepoint = m_pFlowGraphDebugger->IsTracepoint(breakpointItem->flowgraph, breakpointItem->addr);
				roMenu.AppendMenu( MF_STRING | (bIsTracepoint ? MF_CHECKED : MF_UNCHECKED),ID_TRACEPOINT_ENABLE,"Tracepoint");
			}	
		}
				
		break;
	}
		
	return true;
}

void CHyperGraphDialog::ProcessBreakpointMenu( int nMenuOption, HTREEITEM hItem )
{
	switch (nMenuOption)
	{
	case ID_BREAKPOINT_REMOVE_GRAPH:
		{
			m_breakpointsTreeCtrl.RemoveBreakpointsForGraph(hItem);
		}
		break;
	case ID_BREAKPOINT_REMOVE_NODE:
		{
			m_breakpointsTreeCtrl.RemoveBreakpointsForNode(hItem);
		}
		break;
	case ID_BREAKPOINT_REMOVE_PORT:
		{
			m_breakpointsTreeCtrl.RemoveBreakpointForPort(hItem);
		}
		break;
	case ID_BREAKPOINT_ENABLE:
	case ID_TRACEPOINT_ENABLE:
		{
			if (m_pFlowGraphDebugger)
			{
				SBreakpointItem* breakpointItem = reinterpret_cast<SBreakpointItem*>(m_breakpointsTreeCtrl.GetItemData( hItem ));

				if(breakpointItem == NULL)
					return;

				if(nMenuOption == ID_BREAKPOINT_ENABLE)
				{
					const bool bIsEnabled = m_pFlowGraphDebugger->IsBreakpointEnabled(breakpointItem->flowgraph, breakpointItem->addr);
					m_breakpointsTreeCtrl.EnableBreakpoint(hItem, !bIsEnabled);
				}
				else
				{
					const bool bIsTracepoint = m_pFlowGraphDebugger->IsTracepoint(breakpointItem->flowgraph, breakpointItem->addr);
					m_breakpointsTreeCtrl.EnableTracepoint(hItem, !bIsTracepoint);
				}
			}
		}
		break;
	};
}

void CHyperGraphDialog::OnBreakpointsClick( NMHDR* pNMHDR, LRESULT* pResult )
{
		DWORD dw = GetMessagePos();
		CPoint p(GET_X_LPARAM(dw), GET_Y_LPARAM(dw));
		m_breakpointsTreeCtrl.ScreenToClient(&p);

		UINT htFlags = 0;
		HTREEITEM hHitItem= m_breakpointsTreeCtrl.HitTest(p, &htFlags);

		if ((hHitItem != NULL) && (htFlags & TVHT_ONITEM))
		{	
				SBreakpointItem* breakpointItem = reinterpret_cast<SBreakpointItem*>(m_breakpointsTreeCtrl.GetItemData( hHitItem ));

				if(breakpointItem)
				{	
						CFlowGraph* pFlowgraph = GetIEditor()->GetFlowGraphManager()->FindGraph(breakpointItem->flowgraph);

						if(pFlowgraph == NULL)
								return;

						switch (breakpointItem->type)
						{
						case SBreakpointItem::eIT_Graph:
								{
										SetGraph(pFlowgraph);
										m_view.FitFlowGraphToView();
								}
								break;
						case SBreakpointItem::eIT_Node:
						case SBreakpointItem::eIT_Port:
								{
										SetGraph(pFlowgraph);

										CFlowNode* pNode = pFlowgraph->FindFlowNode(breakpointItem->addr.node);

										if(pNode)
										{
												m_view.CenterViewAroundNode(pNode);
												pFlowgraph->UnselectAll();
												pNode->SetSelected(true);
										}
								}
								break;
						}
				}
		}
}
